From a9cde6bb66c4fe8dbf6dc294c1e9d6ef87b45549 Mon Sep 17 00:00:00 2001 From: Michel Hollands Date: Tue, 13 Jul 2021 14:32:08 +0100 Subject: [PATCH 1/3] Update Cortex version Signed-off-by: Michel Hollands --- go.mod | 6 +- go.sum | 36 + .../cortex/pkg/alertmanager/alertmanager.go | 158 +++- .../pkg/alertmanager/alertmanager_http.go | 71 +- .../pkg/alertmanager/alertmanager_metrics.go | 30 +- .../pkg/alertmanager/alertmanager_ring.go | 4 +- .../cortex/pkg/alertmanager/multitenant.go | 77 +- .../cortexproject/cortex/pkg/api/api.go | 18 +- .../cortexproject/cortex/pkg/api/handlers.go | 21 +- .../cortex/pkg/chunk/cache/cache.go | 2 +- .../cortex/pkg/chunk/cache/redis_cache.go | 65 +- .../cortex/pkg/chunk/gcp/gcs_object_client.go | 20 +- .../cortex/pkg/chunk/storage/factory.go | 2 +- .../cortex/pkg/compactor/compactor.go | 12 +- .../cortex/pkg/compactor/compactor_ring.go | 15 +- .../cortexproject/cortex/pkg/cortex/cortex.go | 3 +- .../cortex/pkg/cortex/modules.go | 9 +- .../cortex/pkg/cortex/runtime_config.go | 4 +- .../cortex/pkg/cortexpb/compat.go | 25 + .../cortex/pkg/distributor/distributor.go | 2 +- .../pkg/distributor/distributor_ring.go | 4 +- .../cortex/pkg/distributor/ha_tracker.go | 29 +- .../cortex/pkg/distributor/query.go | 143 ++- .../cortex/pkg/frontend/transport/handler.go | 1 + .../cortex/pkg/ingester/client/compat.go | 32 + .../cortex/pkg/ingester/client/custom.go | 15 + .../cortex/pkg/ingester/client/ingester.pb.go | 843 +++++++++++++++--- .../cortex/pkg/ingester/client/ingester.proto | 11 + .../cortex/pkg/ingester/ingester.go | 41 +- .../cortex/pkg/ingester/ingester_v2.go | 53 +- .../cortex/pkg/ingester/metrics.go | 7 + .../cortex/pkg/ingester/user_state.go | 12 +- .../cortex/pkg/querier/batch/batch.go | 34 +- .../cortex/pkg/querier/batch/merge.go | 7 +- .../pkg/querier/blocks_store_queryable.go | 12 +- .../pkg/querier/distributor_queryable.go | 42 + .../error_translate_queryable.go} | 52 +- .../querier/iterators/chunk_merge_iterator.go | 2 +- .../cortex/pkg/querier/querier.go | 7 +- .../tenantfederation/merge_queryable.go | 46 +- .../cortex/pkg/ring/basic_lifecycler.go | 19 +- .../cortex/pkg/ring/kv/etcd/etcd.go | 7 + .../pkg/ring/kv/memberlist/kv_init_service.go | 50 +- .../ring/kv/memberlist/memberlist_client.go | 167 ++-- .../pkg/ring/kv/memberlist/mergeable.go | 6 +- .../cortex/pkg/ring/kv/memberlist/metrics.go | 32 +- .../cortex/pkg/ring/lifecycler.go | 15 +- .../cortexproject/cortex/pkg/ring/model.go | 34 +- .../cortexproject/cortex/pkg/ring/ring.go | 6 +- .../cortexproject/cortex/pkg/ring/util.go | 2 +- .../cortexproject/cortex/pkg/ruler/compat.go | 136 ++- .../cortexproject/cortex/pkg/ruler/ruler.go | 4 + .../cortex/pkg/ruler/ruler_ring.go | 4 +- .../cortex/pkg/ruler/rulestore/config.go | 10 + .../bucket_store_inmemory_server.go | 10 + .../cortex/pkg/storegateway/gateway.go | 20 +- .../cortex/pkg/storegateway/gateway_ring.go | 38 +- .../pkg/storegateway/sharding_strategy.go | 86 +- .../cortex/pkg/util/limiter/query_limiter.go | 47 +- .../cortexproject/cortex/pkg/util/net.go | 38 +- .../cortexproject/cortex/pkg/util/time.go | 11 + .../cortex/pkg/util/validation/limits.go | 70 +- .../go-openapi/runtime/.gitattributes | 1 + .../go-openapi/runtime/.golangci.yml | 3 +- .../github.com/go-openapi/runtime/.travis.yml | 1 - .../go-openapi/runtime/bytestream.go | 5 + .../github.com/go-openapi/swag/.golangci.yml | 2 + .../go-redis/redis/v8/.golangci.yml | 7 +- .../github.com/go-redis/redis/v8/.travis.yml | 20 - .../github.com/go-redis/redis/v8/CHANGELOG.md | 34 +- vendor/github.com/go-redis/redis/v8/Makefile | 11 +- vendor/github.com/go-redis/redis/v8/README.md | 88 +- .../github.com/go-redis/redis/v8/cluster.go | 79 +- .../go-redis/redis/v8/cluster_commands.go | 74 ++ .../github.com/go-redis/redis/v8/command.go | 497 +++++++++++ .../github.com/go-redis/redis/v8/commands.go | 295 +++++- vendor/github.com/go-redis/redis/v8/error.go | 9 +- vendor/github.com/go-redis/redis/v8/go.mod | 10 +- vendor/github.com/go-redis/redis/v8/go.sum | 55 +- .../redis/v8/internal/hashtag/hashtag.go | 2 +- .../go-redis/redis/v8/internal/hscan/hscan.go | 201 +++++ .../redis/v8/internal/hscan/structmap.go | 93 ++ .../go-redis/redis/v8/internal/instruments.go | 4 +- .../go-redis/redis/v8/internal/internal.go | 4 + .../go-redis/redis/v8/internal/log.go | 2 + .../go-redis/redis/v8/internal/pool/conn.go | 53 +- .../go-redis/redis/v8/internal/pool/pool.go | 9 +- .../redis/v8/internal/pool/pool_sticky.go | 3 +- .../redis/v8/internal/proto/reader.go | 19 +- .../go-redis/redis/v8/internal/proto/scan.go | 8 +- .../go-redis/redis/v8/internal/rand/rand.go | 5 + .../go-redis/redis/v8/internal/util.go | 51 +- .../github.com/go-redis/redis/v8/options.go | 32 +- vendor/github.com/go-redis/redis/v8/pubsub.go | 211 +++-- vendor/github.com/go-redis/redis/v8/redis.go | 154 ++-- .../go-redis/redis/v8/renovate.json | 5 - vendor/github.com/go-redis/redis/v8/ring.go | 1 - vendor/github.com/go-redis/redis/v8/script.go | 18 +- .../github.com/go-redis/redis/v8/sentinel.go | 94 +- vendor/github.com/go-redis/redis/v8/tx.go | 7 +- .../github.com/go-redis/redis/v8/universal.go | 18 +- .../hashicorp/memberlist/event_delegate.go | 9 +- .../github.com/hashicorp/memberlist/state.go | 13 +- .../github.com/hashicorp/memberlist/util.go | 18 +- .../github.com/jessevdk/go-flags/.travis.yml | 9 +- vendor/github.com/jessevdk/go-flags/README.md | 5 + .../jessevdk/go-flags/check_crosscompile.sh | 4 + .../github.com/jessevdk/go-flags/command.go | 4 +- .../jessevdk/go-flags/completion.go | 10 +- .../github.com/jessevdk/go-flags/convert.go | 9 + vendor/github.com/jessevdk/go-flags/error.go | 4 + vendor/github.com/jessevdk/go-flags/flags.go | 7 +- vendor/github.com/jessevdk/go-flags/go.mod | 5 + vendor/github.com/jessevdk/go-flags/go.sum | 2 + vendor/github.com/jessevdk/go-flags/group.go | 23 + vendor/github.com/jessevdk/go-flags/help.go | 35 +- vendor/github.com/jessevdk/go-flags/ini.go | 36 +- vendor/github.com/jessevdk/go-flags/man.go | 76 +- vendor/github.com/jessevdk/go-flags/option.go | 136 ++- vendor/github.com/jessevdk/go-flags/parser.go | 102 ++- .../github.com/jessevdk/go-flags/termsize.go | 25 +- .../jessevdk/go-flags/termsize_nosysioctl.go | 2 +- .../jessevdk/go-flags/termsize_windows.go | 85 ++ .../jessevdk/go-flags/tiocgwinsz_bsdish.go | 7 - .../jessevdk/go-flags/tiocgwinsz_linux.go | 7 - .../jessevdk/go-flags/tiocgwinsz_other.go | 7 - .../alertmanager/asset/assets_vfsdata.go | 4 +- .../prometheus/alertmanager/config/config.go | 6 +- .../alertmanager/dispatch/dispatch.go | 108 ++- .../alertmanager/provider/mem/mem.go | 42 +- .../alertmanager/provider/provider.go | 2 +- .../prometheus/alertmanager/ui/Dockerfile | 5 +- .../prometheus/common/config/config.go | 17 +- .../prometheus/common/config/http_config.go | 87 +- .../prometheus/common/model/labels.go | 8 + vendor/go.opentelemetry.io/otel/.gitignore | 7 +- vendor/go.opentelemetry.io/otel/CHANGELOG.md | 524 ++++++++++- vendor/go.opentelemetry.io/otel/CODEOWNERS | 8 +- .../go.opentelemetry.io/otel/CONTRIBUTING.md | 59 +- vendor/go.opentelemetry.io/otel/Makefile | 208 +++-- .../go.opentelemetry.io/otel/Makefile.proto | 72 -- vendor/go.opentelemetry.io/otel/README.md | 122 +-- vendor/go.opentelemetry.io/otel/RELEASING.md | 6 +- vendor/go.opentelemetry.io/otel/VERSIONING.md | 217 +++++ .../otel/api/correlation/doc.go | 19 - .../otel/api/correlation/map.go | 176 ---- .../otel/api/metric/async.go | 217 ----- .../otel/api/metric/counter.go | 95 -- .../otel/api/metric/descriptor.go | 77 -- .../otel/api/metric/doc.go | 49 - .../otel/api/metric/kind.go | 79 -- .../otel/api/metric/must.go | 222 ----- .../otel/api/metric/numberkind_string.go | 24 - .../otel/api/metric/observer.go | 124 --- .../otel/api/metric/sync.go | 192 ---- .../otel/api/metric/updowncounter.go | 96 -- .../otel/api/metric/valuerecorder.go | 97 -- .../otel/api/propagation/propagation.go | 143 --- .../go.opentelemetry.io/otel/api/trace/api.go | 273 ------ .../otel/api/trace/b3_propagator.go | 343 ------- .../otel/api/trace/context.go | 55 -- .../go.opentelemetry.io/otel/api/trace/doc.go | 15 - .../otel/api/trace/noop_span.go | 79 -- .../otel/api/trace/span_context.go | 197 ---- .../api/trace/trace_context_propagator.go | 152 ---- .../doc.go} | 16 +- .../otel/{label => attribute}/encoder.go | 6 +- .../otel/{label => attribute}/iterator.go | 14 +- .../otel/{label => attribute}/key.go | 71 +- .../otel/{label => attribute}/kv.go | 52 +- .../otel/{label => attribute}/set.go | 7 +- .../otel/{label => attribute}/type_string.go | 18 +- .../otel/{label => attribute}/value.go | 154 +--- .../go.opentelemetry.io/otel/codes/codes.go | 159 ++-- .../global/propagation.go => codes/doc.go} | 25 +- vendor/go.opentelemetry.io/otel/doc.go | 23 + .../go.opentelemetry.io/otel/error_handler.go | 2 +- .../go.opentelemetry.io/otel/get_main_pkgs.sh | 17 +- vendor/go.opentelemetry.io/otel/go.mod | 51 +- vendor/go.opentelemetry.io/otel/go.sum | 8 +- .../otel/{api/global => }/handler.go | 22 +- .../baggage/baggage.go} | 172 +++- .../internal => internal/global}/meter.go | 55 +- .../otel/internal/global/propagator.go | 82 ++ .../internal => internal/global}/state.go | 87 +- .../internal => internal/global}/trace.go | 101 ++- .../otel/internal/rawhelpers.go | 36 - .../trace/noop/noop.go} | 20 +- .../go.opentelemetry.io/otel/metric/LICENSE | 201 +++++ .../otel/{api => }/metric/config.go | 29 +- vendor/go.opentelemetry.io/otel/metric/doc.go | 67 ++ .../otel/{api => metric}/global/metric.go | 20 +- vendor/go.opentelemetry.io/otel/metric/go.mod | 54 ++ vendor/go.opentelemetry.io/otel/metric/go.sum | 15 + .../otel/metric/instrumentkind_string.go | 28 + .../{api/metric/meter.go => metric/metric.go} | 337 ++++++- .../otel/metric/metric_instrument.go | 777 ++++++++++++++++ .../metric/noop.go => metric/metric_noop.go} | 17 +- .../sdkapi.go => metric/metric_sdkapi.go} | 19 +- .../{api/propagation => metric/number}/doc.go | 11 +- .../metric => metric/number}/kind_string.go | 14 +- .../{api/metric => metric/number}/number.go | 112 ++- .../otel/metric/registry/doc.go | 24 + .../{api => }/metric/registry/registry.go | 32 +- .../go.opentelemetry.io/otel/pre_release.sh | 14 +- .../go.opentelemetry.io/otel/propagation.go | 31 + .../baggage.go} | 67 +- .../otel/propagation/doc.go | 28 + .../otel/propagation/propagation.go | 105 +++ .../otel/propagation/trace_context.go | 178 ++++ vendor/go.opentelemetry.io/otel/tag.sh | 2 +- .../otel/{api/global => }/trace.go | 26 +- vendor/go.opentelemetry.io/otel/trace/LICENSE | 201 +++++ .../go.opentelemetry.io/otel/trace/config.go | 205 +++++ .../go.opentelemetry.io/otel/trace/context.go | 61 ++ vendor/go.opentelemetry.io/otel/trace/doc.go | 70 ++ vendor/go.opentelemetry.io/otel/trace/go.mod | 53 ++ vendor/go.opentelemetry.io/otel/trace/go.sum | 15 + .../otel/{otel.go => trace/nonrecording.go} | 20 +- vendor/go.opentelemetry.io/otel/trace/noop.go | 84 ++ .../go.opentelemetry.io/otel/trace/trace.go | 673 ++++++++++++++ .../otel/{api => }/unit/doc.go | 7 +- .../otel/{api => }/unit/unit.go | 2 +- .../otel/{label/doc.go => version.go} | 8 +- vendor/golang.org/x/net/http2/ascii.go | 49 + vendor/golang.org/x/net/http2/headermap.go | 7 +- vendor/golang.org/x/net/http2/server.go | 26 +- vendor/golang.org/x/net/http2/transport.go | 30 +- vendor/golang.org/x/net/http2/write.go | 7 +- vendor/modules.txt | 45 +- 230 files changed, 9794 insertions(+), 5011 deletions(-) rename vendor/github.com/cortexproject/cortex/pkg/{api/queryable.go => querier/error_translate_queryable.go} (70%) create mode 100644 vendor/github.com/go-openapi/runtime/.gitattributes delete mode 100644 vendor/github.com/go-redis/redis/v8/.travis.yml create mode 100644 vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go create mode 100644 vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go delete mode 100644 vendor/github.com/go-redis/redis/v8/renovate.json create mode 100644 vendor/github.com/jessevdk/go-flags/go.mod create mode 100644 vendor/github.com/jessevdk/go-flags/go.sum create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_windows.go delete mode 100644 vendor/github.com/jessevdk/go-flags/tiocgwinsz_bsdish.go delete mode 100644 vendor/github.com/jessevdk/go-flags/tiocgwinsz_linux.go delete mode 100644 vendor/github.com/jessevdk/go-flags/tiocgwinsz_other.go delete mode 100644 vendor/go.opentelemetry.io/otel/Makefile.proto create mode 100644 vendor/go.opentelemetry.io/otel/VERSIONING.md delete mode 100644 vendor/go.opentelemetry.io/otel/api/correlation/doc.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/correlation/map.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/async.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/counter.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/descriptor.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/doc.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/kind.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/must.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/numberkind_string.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/observer.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/sync.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/updowncounter.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/metric/valuerecorder.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/propagation/propagation.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/trace/api.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/trace/b3_propagator.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/trace/context.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/trace/doc.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/trace/noop_span.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/trace/span_context.go delete mode 100644 vendor/go.opentelemetry.io/otel/api/trace/trace_context_propagator.go rename vendor/go.opentelemetry.io/otel/{api/trace/noop_trace_provider.go => attribute/doc.go} (63%) rename vendor/go.opentelemetry.io/otel/{label => attribute}/encoder.go (97%) rename vendor/go.opentelemetry.io/otel/{label => attribute}/iterator.go (90%) rename vendor/go.opentelemetry.io/otel/{label => attribute}/key.go (58%) rename vendor/go.opentelemetry.io/otel/{label => attribute}/kv.go (67%) rename vendor/go.opentelemetry.io/otel/{label => attribute}/set.go (97%) rename vendor/go.opentelemetry.io/otel/{label => attribute}/type_string.go (61%) rename vendor/go.opentelemetry.io/otel/{label => attribute}/value.go (51%) rename vendor/go.opentelemetry.io/otel/{api/global/propagation.go => codes/doc.go} (53%) rename vendor/go.opentelemetry.io/otel/{api/global => }/handler.go (82%) rename vendor/go.opentelemetry.io/otel/{api/correlation/context.go => internal/baggage/baggage.go} (55%) rename vendor/go.opentelemetry.io/otel/{api/global/internal => internal/global}/meter.go (83%) create mode 100644 vendor/go.opentelemetry.io/otel/internal/global/propagator.go rename vendor/go.opentelemetry.io/otel/{api/global/internal => internal/global}/state.go (50%) rename vendor/go.opentelemetry.io/otel/{api/global/internal => internal/global}/trace.go (51%) rename vendor/go.opentelemetry.io/otel/{api/trace/noop_trace.go => internal/trace/noop/noop.go} (63%) create mode 100644 vendor/go.opentelemetry.io/otel/metric/LICENSE rename vendor/go.opentelemetry.io/otel/{api => }/metric/config.go (80%) create mode 100644 vendor/go.opentelemetry.io/otel/metric/doc.go rename vendor/go.opentelemetry.io/otel/{api => metric}/global/metric.go (74%) create mode 100644 vendor/go.opentelemetry.io/otel/metric/go.mod create mode 100644 vendor/go.opentelemetry.io/otel/metric/go.sum create mode 100644 vendor/go.opentelemetry.io/otel/metric/instrumentkind_string.go rename vendor/go.opentelemetry.io/otel/{api/metric/meter.go => metric/metric.go} (50%) create mode 100644 vendor/go.opentelemetry.io/otel/metric/metric_instrument.go rename vendor/go.opentelemetry.io/otel/{api/metric/noop.go => metric/metric_noop.go} (69%) rename vendor/go.opentelemetry.io/otel/{api/metric/sdkapi.go => metric/metric_sdkapi.go} (81%) rename vendor/go.opentelemetry.io/otel/{api/propagation => metric/number}/doc.go (60%) rename vendor/go.opentelemetry.io/otel/{api/metric => metric/number}/kind_string.go (56%) rename vendor/go.opentelemetry.io/otel/{api/metric => metric/number}/number.go (86%) create mode 100644 vendor/go.opentelemetry.io/otel/metric/registry/doc.go rename vendor/go.opentelemetry.io/otel/{api => }/metric/registry/registry.go (83%) create mode 100644 vendor/go.opentelemetry.io/otel/propagation.go rename vendor/go.opentelemetry.io/otel/{api/correlation/correlation_context_propagator.go => propagation/baggage.go} (53%) create mode 100644 vendor/go.opentelemetry.io/otel/propagation/doc.go create mode 100644 vendor/go.opentelemetry.io/otel/propagation/propagation.go create mode 100644 vendor/go.opentelemetry.io/otel/propagation/trace_context.go rename vendor/go.opentelemetry.io/otel/{api/global => }/trace.go (58%) create mode 100644 vendor/go.opentelemetry.io/otel/trace/LICENSE create mode 100644 vendor/go.opentelemetry.io/otel/trace/config.go create mode 100644 vendor/go.opentelemetry.io/otel/trace/context.go create mode 100644 vendor/go.opentelemetry.io/otel/trace/doc.go create mode 100644 vendor/go.opentelemetry.io/otel/trace/go.mod create mode 100644 vendor/go.opentelemetry.io/otel/trace/go.sum rename vendor/go.opentelemetry.io/otel/{otel.go => trace/nonrecording.go} (60%) create mode 100644 vendor/go.opentelemetry.io/otel/trace/noop.go create mode 100644 vendor/go.opentelemetry.io/otel/trace/trace.go rename vendor/go.opentelemetry.io/otel/{api => }/unit/doc.go (65%) rename vendor/go.opentelemetry.io/otel/{api => }/unit/unit.go (92%) rename vendor/go.opentelemetry.io/otel/{label/doc.go => version.go} (78%) create mode 100644 vendor/golang.org/x/net/http2/ascii.go diff --git a/go.mod b/go.mod index ffa5693228f1..3e760dc157fd 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/cespare/xxhash/v2 v2.1.1 github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448 // indirect github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf - github.com/cortexproject/cortex v1.9.1-0.20210527130655-bd720c688ffa + github.com/cortexproject/cortex v1.9.1-0.20210712083557-733f7de5c81f github.com/davecgh/go-spew v1.1.1 github.com/docker/docker v20.10.6+incompatible github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 // indirect @@ -54,7 +54,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.10.0 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.23.0 + github.com/prometheus/common v0.26.1-0.20210603143733-6ef301f414bf github.com/prometheus/prometheus v1.8.2-0.20210510213326-e313ffa8abf6 github.com/segmentio/fasthash v1.0.2 github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 @@ -69,7 +69,7 @@ require ( go.uber.org/atomic v1.7.0 go.uber.org/goleak v1.1.10 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 - golang.org/x/net v0.0.0-20210505214959-0714010a04ed + golang.org/x/net v0.0.0-20210525063256-abc453219eb5 golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 google.golang.org/api v0.46.0 google.golang.org/grpc v1.37.0 diff --git a/go.sum b/go.sum index d3a2e85c16ca..fea8edfb2145 100644 --- a/go.sum +++ b/go.sum @@ -349,6 +349,8 @@ github.com/cortexproject/cortex v1.7.1-0.20210316085356-3fedc1108a49/go.mod h1:/ github.com/cortexproject/cortex v1.8.1-0.20210422151339-cf1c444e0905/go.mod h1:xxm4/CLvTmDxwE7yXwtClR4dIvkG4S09o5DygPOgc1U= github.com/cortexproject/cortex v1.9.1-0.20210527130655-bd720c688ffa h1:Z9Mi0HskMjHb606OFa89kv7hyfIVcriis0Ssh9WrbyM= github.com/cortexproject/cortex v1.9.1-0.20210527130655-bd720c688ffa/go.mod h1:aHcimX/nX9yUmk2iOWeQrE3hTh3gqIe6QOOo/6RkBlU= +github.com/cortexproject/cortex v1.9.1-0.20210712083557-733f7de5c81f h1:+77Qgcyyz7iwlZd+m9n5c/4Zw5CSn5IwC7wV2xDIVV4= +github.com/cortexproject/cortex v1.9.1-0.20210712083557-733f7de5c81f/go.mod h1:I9ew9PB8l8+YI+Qq85XJ2wEkAg8y8dAX1z/g6SFZ8g0= github.com/couchbase/go-couchbase v0.0.0-20180501122049-16db1f1fe037/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= github.com/couchbase/gomemcached v0.0.0-20180502221210-0da75df14530/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= @@ -510,6 +512,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -584,6 +587,8 @@ github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiS github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= github.com/go-openapi/runtime v0.19.26 h1:K/6PoVNj5WJXUnMk+VEbELeXjtBkCS1UxTDa04tdXE0= github.com/go-openapi/runtime v0.19.26/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= +github.com/go-openapi/runtime v0.19.28 h1:9lYu6axek8LJrVkMVViVirRcpoaCxXX7+sSvmizGVnA= +github.com/go-openapi/runtime v0.19.28/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= @@ -625,6 +630,8 @@ github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5H github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= @@ -642,6 +649,8 @@ github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w github.com/go-redis/redis/v8 v8.0.0-beta.10.0.20200905143926-df7fe4e2ce72/go.mod h1:CJP1ZIHwhosNYwIdaHPZK9vHsM3+roNBaZ7U9Of1DXc= github.com/go-redis/redis/v8 v8.2.3 h1:eNesND+DWt/sjQOtPFxAbQkTIXaXX00qNLxjVWkZ70k= github.com/go-redis/redis/v8 v8.2.3/go.mod h1:ysgGY09J/QeDYbu3HikWEIPCwaeOkuNoTgKayTEaEOw= +github.com/go-redis/redis/v8 v8.9.0 h1:FTTbB7WqlXfVNdVv0SsxA+oVi0bAwit6bMe3IUucq2o= +github.com/go-redis/redis/v8 v8.9.0/go.mod h1:ik7vb7+gm8Izylxu6kf6wG26/t2VljgCfSQ1DM4O1uU= github.com/go-sql-driver/mysql v0.0.0-20180618115901-749ddf1598b4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -957,6 +966,8 @@ github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/memberlist v0.2.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.2.3 h1:BwZa5IjREr75J0am7nblP+X5i95Rmp8EEbMI5vkUWdA= +github.com/hashicorp/memberlist v0.2.3/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q= github.com/hashicorp/raft v1.0.1-0.20190409200437-d9fe23f7d472/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= github.com/hashicorp/raft-boltdb v0.0.0-20150201200839-d1e82c1ec3f1/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= @@ -1023,6 +1034,8 @@ github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee/go.mod h1:N0t2vlmpe github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= @@ -1293,6 +1306,7 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1303,6 +1317,7 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/openconfig/gnmi v0.0.0-20180912164834-33a1865c3029/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1373,6 +1388,8 @@ github.com/prometheus/alertmanager v0.21.1-0.20201106142418-c39b78780054/go.mod github.com/prometheus/alertmanager v0.21.1-0.20210310093010-0f9cab6991e6/go.mod h1:MTqVn+vIupE0dzdgo+sMcNCp37SCAi8vPrvKTTnTz9g= github.com/prometheus/alertmanager v0.21.1-0.20210422101724-8176f78a70e1 h1:i7S+d1wua/WE/ipFcX2hSUN6Fqn+8+pMQPjFTBxGWFE= github.com/prometheus/alertmanager v0.21.1-0.20210422101724-8176f78a70e1/go.mod h1:gsEqwD5BHHW9RNKvCuPOrrTMiP5I+faJUyLXvnivHik= +github.com/prometheus/alertmanager v0.22.1-0.20210603124511-8b584eb2265e h1:FNLZCG1rR9QPbkwYLMiy7TnI4WRB7TeipcxkrbszN4E= +github.com/prometheus/alertmanager v0.22.1-0.20210603124511-8b584eb2265e/go.mod h1:ntrorfzWQ1I9mhJK7AO71w4xMUgM4SxmwbtyQgAWZz0= github.com/prometheus/client_golang v0.0.0-20180328130430-f504d69affe1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1424,6 +1441,9 @@ github.com/prometheus/common v0.20.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.21.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.23.0 h1:GXWvPYuTUenIa+BhOq/x+L/QZzCqASkVRny5KTlPDGM= github.com/prometheus/common v0.23.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= +github.com/prometheus/common v0.24.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= +github.com/prometheus/common v0.26.1-0.20210603143733-6ef301f414bf h1:w+U3wF/6JRY6+MNfxTodIBw6dZaE11Y+Arg3bRLqatI= +github.com/prometheus/common v0.26.1-0.20210603143733-6ef301f414bf/go.mod h1:LdLj/WiR+LL0ThCPrtSZbijrsxInIhizDTiPlJhPPq4= github.com/prometheus/exporter-toolkit v0.5.0/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= github.com/prometheus/exporter-toolkit v0.5.1/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= github.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289 h1:dTUS1vaLWq+Y6XKOTnrFpoVsQKLCbCp1OLj24TDi7oM= @@ -1671,6 +1691,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v1.0.0/go.mod h1:IoImgRak9i3zJyuxOKUP1v4UZd1tMoKkq/Cimt1uhCg= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1735,6 +1756,13 @@ go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E= go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0= +go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.starlark.net v0.0.0-20200901195727-6e684ef5eeee/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1904,9 +1932,12 @@ golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210324051636-2c4c8ecb7826/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210505214959-0714010a04ed h1:V9kAVxLvz1lkufatrpHuUVyJ/5tR3Ms7rk951P4mI98= golang.org/x/net v0.0.0-20210505214959-0714010a04ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1925,6 +1956,8 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c h1:SgVl/sCtkicsS7psKkje4H9YtjdEl3xsYh7N+5TDHqY= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2032,6 +2065,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2043,6 +2077,7 @@ golang.org/x/sys v0.0.0-20210314195730-07df6a141424/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= @@ -2157,6 +2192,7 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201119054027-25dc3e1ccc3c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= diff --git a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager.go b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager.go index db75214ffcef..fe89550f9503 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager.go +++ b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager.go @@ -166,6 +166,7 @@ func New(cfg *Config, reg *prometheus.Registry) (*Alertmanager, error) { Name: "alertmanager_notification_rate_limited_total", Help: "Number of rate-limited notifications per integration.", }, []string{"integration"}), // "integration" is consistent with other alertmanager metrics. + } am.registry = reg @@ -241,7 +242,12 @@ func New(cfg *Config, reg *prometheus.Registry) (*Alertmanager, error) { am.wg.Done() }() - am.alerts, err = mem.NewAlerts(context.Background(), am.marker, 30*time.Minute, am.logger) + var callback mem.AlertStoreCallback + if am.cfg.Limits != nil { + callback = newAlertsLimiter(am.cfg.UserID, am.cfg.Limits, reg) + } + + am.alerts, err = mem.NewAlerts(context.Background(), am.marker, 30*time.Minute, callback, am.logger) if err != nil { return nil, fmt.Errorf("failed to create alerts: %v", err) } @@ -278,7 +284,7 @@ func New(cfg *Config, reg *prometheus.Registry) (*Alertmanager, error) { am.mux.Handle(a, http.NotFoundHandler()) } - am.dispatcherMetrics = dispatch.NewDispatcherMetrics(am.registry) + am.dispatcherMetrics = dispatch.NewDispatcherMetrics(true, am.registry) //TODO: From this point onward, the alertmanager _might_ receive requests - we need to make sure we've settled and are ready. return am, nil @@ -382,6 +388,7 @@ func (am *Alertmanager) ApplyConfig(userID string, conf *config.Config, rawCfg s pipeline, am.marker, timeoutFunc, + &dispatcherLimits{tenant: am.cfg.UserID, limits: am.cfg.Limits}, log.With(am.logger, "component", "dispatcher"), am.dispatcherMetrics, ) @@ -574,3 +581,150 @@ func (t *tenantRateLimits) RateLimit() rate.Limit { func (t *tenantRateLimits) Burst() int { return t.limits.NotificationBurstSize(t.tenant, t.integration) } + +type dispatcherLimits struct { + tenant string + limits Limits +} + +func (g *dispatcherLimits) MaxNumberOfAggregationGroups() int { + return g.limits.AlertmanagerMaxDispatcherAggregationGroups(g.tenant) +} + +var ( + errTooManyAlerts = "too many alerts, limit: %d" + errAlertsTooBig = "alerts too big, total size limit: %d bytes" +) + +// alertsLimiter limits the number and size of alerts being received by the Alertmanager. +// We consider an alert unique based on its fingerprint (a hash of its labels) and +// its size it's determined by the sum of bytes of its labels, annotations, and generator URL. +type alertsLimiter struct { + tenant string + limits Limits + + failureCounter prometheus.Counter + + mx sync.Mutex + sizes map[model.Fingerprint]int + count int + totalSize int +} + +func newAlertsLimiter(tenant string, limits Limits, reg prometheus.Registerer) *alertsLimiter { + limiter := &alertsLimiter{ + tenant: tenant, + limits: limits, + sizes: map[model.Fingerprint]int{}, + failureCounter: promauto.With(reg).NewCounter(prometheus.CounterOpts{ + Name: "alertmanager_alerts_insert_limited_total", + Help: "Number of failures to insert new alerts to in-memory alert store.", + }), + } + + promauto.With(reg).NewGaugeFunc(prometheus.GaugeOpts{ + Name: "alertmanager_alerts_limiter_current_alerts", + Help: "Number of alerts tracked by alerts limiter.", + }, func() float64 { + c, _ := limiter.currentStats() + return float64(c) + }) + + promauto.With(reg).NewGaugeFunc(prometheus.GaugeOpts{ + Name: "alertmanager_alerts_limiter_current_alerts_size_bytes", + Help: "Total size of alerts tracked by alerts limiter.", + }, func() float64 { + _, s := limiter.currentStats() + return float64(s) + }) + + return limiter +} + +func (a *alertsLimiter) PreStore(alert *types.Alert, existing bool) error { + if alert == nil { + return nil + } + + fp := alert.Fingerprint() + + countLimit := a.limits.AlertmanagerMaxAlertsCount(a.tenant) + sizeLimit := a.limits.AlertmanagerMaxAlertsSizeBytes(a.tenant) + + sizeDiff := alertSize(alert.Alert) + + a.mx.Lock() + defer a.mx.Unlock() + + if !existing && countLimit > 0 && (a.count+1) > countLimit { + a.failureCounter.Inc() + return fmt.Errorf(errTooManyAlerts, countLimit) + } + + if existing { + sizeDiff -= a.sizes[fp] + } + + if sizeLimit > 0 && (a.totalSize+sizeDiff) > sizeLimit { + a.failureCounter.Inc() + return fmt.Errorf(errAlertsTooBig, sizeLimit) + } + + return nil +} + +func (a *alertsLimiter) PostStore(alert *types.Alert, existing bool) { + if alert == nil { + return + } + + newSize := alertSize(alert.Alert) + fp := alert.Fingerprint() + + a.mx.Lock() + defer a.mx.Unlock() + + if existing { + a.totalSize -= a.sizes[fp] + } else { + a.count++ + } + a.sizes[fp] = newSize + a.totalSize += newSize +} + +func (a *alertsLimiter) PostDelete(alert *types.Alert) { + if alert == nil { + return + } + + fp := alert.Fingerprint() + + a.mx.Lock() + defer a.mx.Unlock() + + a.totalSize -= a.sizes[fp] + delete(a.sizes, fp) + a.count-- +} + +func (a *alertsLimiter) currentStats() (count, totalSize int) { + a.mx.Lock() + defer a.mx.Unlock() + + return a.count, a.totalSize +} + +func alertSize(alert model.Alert) int { + size := 0 + for l, v := range alert.Labels { + size += len(l) + size += len(v) + } + for l, v := range alert.Annotations { + size += len(l) + size += len(v) + } + size += len(alert.GeneratorURL) + return size +} diff --git a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_http.go b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_http.go index 0efeebde15ab..f0afeb2775fe 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_http.go +++ b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_http.go @@ -11,7 +11,7 @@ import ( ) var ( - statusPageTemplate = template.Must(template.New("main").Parse(` + ringStatusPageTemplate = template.Must(template.New("ringStatusPage").Parse(` @@ -23,14 +23,43 @@ var (

{{ .Message }}

`)) + + statusTemplate = template.Must(template.New("statusPage").Parse(` + + + Cortex Alertmanager Status + +

Cortex Alertmanager Status

+ {{ if not .ClusterInfo }} +

Alertmanager gossip-based clustering is disabled.

+ {{ else }} +

Node

+
+
Name
{{.ClusterInfo.self.Name}}
+
Addr
{{.ClusterInfo.self.Addr}}
+
Port
{{.ClusterInfo.self.Port}}
+
+

Members

+ {{ with .ClusterInfo.members }} + + + {{ range . }} + + {{ end }} +
NameAddr
{{ .Name }}{{ .Addr }}
+ {{ else }} +

No peers

+ {{ end }} + {{ end }} + + `)) ) -func writeMessage(w http.ResponseWriter, message string) { +func writeRingStatusMessage(w http.ResponseWriter, message string) { w.WriteHeader(http.StatusOK) - err := statusPageTemplate.Execute(w, struct { + err := ringStatusPageTemplate.Execute(w, struct { Message string }{Message: message}) - if err != nil { level.Error(util_log.Logger).Log("msg", "unable to serve alertmanager ring page", "err", err) } @@ -38,16 +67,46 @@ func writeMessage(w http.ResponseWriter, message string) { func (am *MultitenantAlertmanager) RingHandler(w http.ResponseWriter, req *http.Request) { if !am.cfg.ShardingEnabled { - writeMessage(w, "Alertmanager has no ring because sharding is disabled.") + writeRingStatusMessage(w, "Alertmanager has no ring because sharding is disabled.") return } if am.State() != services.Running { // we cannot read the ring before the alertmanager is in Running state, // because that would lead to race condition. - writeMessage(w, "Alertmanager is not running yet.") + writeRingStatusMessage(w, "Alertmanager is not running yet.") return } am.ring.ServeHTTP(w, req) } + +// GetStatusHandler returns the status handler for this multi-tenant +// alertmanager. +func (am *MultitenantAlertmanager) GetStatusHandler() StatusHandler { + return StatusHandler{ + am: am, + } +} + +// StatusHandler shows the status of the alertmanager. +type StatusHandler struct { + am *MultitenantAlertmanager +} + +// ServeHTTP serves the status of the alertmanager. +func (s StatusHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) { + var clusterInfo map[string]interface{} + if s.am.peer != nil { + clusterInfo = s.am.peer.Info() + } + err := statusTemplate.Execute(w, struct { + ClusterInfo map[string]interface{} + }{ + ClusterInfo: clusterInfo, + }) + if err != nil { + level.Error(util_log.Logger).Log("msg", "unable to serve alertmanager status page", "err", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} diff --git a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_metrics.go b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_metrics.go index d62ea90b178e..a5371f6c95bf 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_metrics.go +++ b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_metrics.go @@ -59,7 +59,11 @@ type alertmanagerMetrics struct { persistTotal *prometheus.Desc persistFailed *prometheus.Desc - notificationRateLimited *prometheus.Desc + notificationRateLimited *prometheus.Desc + dispatcherAggregationGroupsLimitReached *prometheus.Desc + insertAlertFailures *prometheus.Desc + alertsLimiterAlertsCount *prometheus.Desc + alertsLimiterAlertsSize *prometheus.Desc } func newAlertmanagerMetrics() *alertmanagerMetrics { @@ -209,6 +213,22 @@ func newAlertmanagerMetrics() *alertmanagerMetrics { "cortex_alertmanager_notification_rate_limited_total", "Total number of rate-limited notifications per integration.", []string{"user", "integration"}, nil), + dispatcherAggregationGroupsLimitReached: prometheus.NewDesc( + "cortex_alertmanager_dispatcher_aggregation_group_limit_reached_total", + "Number of times when dispatcher failed to create new aggregation group due to limit.", + []string{"user"}, nil), + insertAlertFailures: prometheus.NewDesc( + "cortex_alertmanager_alerts_insert_limited_total", + "Total number of failures to store alert due to hitting alertmanager limits.", + []string{"user"}, nil), + alertsLimiterAlertsCount: prometheus.NewDesc( + "cortex_alertmanager_alerts_limiter_current_alerts", + "Number of alerts tracked by alerts limiter.", + []string{"user"}, nil), + alertsLimiterAlertsSize: prometheus.NewDesc( + "cortex_alertmanager_alerts_limiter_current_alerts_size_bytes", + "Total size of alerts tracked by alerts limiter.", + []string{"user"}, nil), } } @@ -259,6 +279,10 @@ func (m *alertmanagerMetrics) Describe(out chan<- *prometheus.Desc) { out <- m.persistTotal out <- m.persistFailed out <- m.notificationRateLimited + out <- m.dispatcherAggregationGroupsLimitReached + out <- m.insertAlertFailures + out <- m.alertsLimiterAlertsCount + out <- m.alertsLimiterAlertsSize } func (m *alertmanagerMetrics) Collect(out chan<- prometheus.Metric) { @@ -306,4 +330,8 @@ func (m *alertmanagerMetrics) Collect(out chan<- prometheus.Metric) { data.SendSumOfCounters(out, m.persistFailed, "alertmanager_state_persist_failed_total") data.SendSumOfCountersPerUserWithLabels(out, m.notificationRateLimited, "alertmanager_notification_rate_limited_total", "integration") + data.SendSumOfCountersPerUser(out, m.dispatcherAggregationGroupsLimitReached, "alertmanager_dispatcher_aggregation_group_limit_reached_total") + data.SendSumOfCountersPerUser(out, m.insertAlertFailures, "alertmanager_alerts_insert_limited_total") + data.SendSumOfGaugesPerUser(out, m.alertsLimiterAlertsCount, "alertmanager_alerts_limiter_current_alerts") + data.SendSumOfGaugesPerUser(out, m.alertsLimiterAlertsSize, "alertmanager_alerts_limiter_current_alerts_size_bytes") } diff --git a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_ring.go b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_ring.go index 04d08d2d6560..0c60d0f69c57 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_ring.go +++ b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/alertmanager_ring.go @@ -76,8 +76,8 @@ func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { // Ring flags cfg.KVStore.RegisterFlagsWithPrefix(rfprefix, "alertmanagers/", f) - f.DurationVar(&cfg.HeartbeatPeriod, rfprefix+"heartbeat-period", 15*time.Second, "Period at which to heartbeat to the ring.") - f.DurationVar(&cfg.HeartbeatTimeout, rfprefix+"heartbeat-timeout", time.Minute, "The heartbeat timeout after which alertmanagers are considered unhealthy within the ring.") + f.DurationVar(&cfg.HeartbeatPeriod, rfprefix+"heartbeat-period", 15*time.Second, "Period at which to heartbeat to the ring. 0 = disabled.") + f.DurationVar(&cfg.HeartbeatTimeout, rfprefix+"heartbeat-timeout", time.Minute, "The heartbeat timeout after which alertmanagers are considered unhealthy within the ring. 0 = never (timeout disabled).") f.IntVar(&cfg.ReplicationFactor, rfprefix+"replication-factor", 3, "The replication factor to use when sharding the alertmanager.") f.BoolVar(&cfg.ZoneAwarenessEnabled, rfprefix+"zone-awareness-enabled", false, "True to enable zone-awareness and replicate alerts across different availability zones.") diff --git a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/multitenant.go b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/multitenant.go index c87c16b72b45..096f9f26758e 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/alertmanager/multitenant.go +++ b/vendor/github.com/cortexproject/cortex/pkg/alertmanager/multitenant.go @@ -4,7 +4,6 @@ import ( "context" "flag" "fmt" - "html/template" "io/ioutil" "net/http" "net/url" @@ -38,6 +37,7 @@ import ( "github.com/cortexproject/cortex/pkg/util" "github.com/cortexproject/cortex/pkg/util/concurrency" "github.com/cortexproject/cortex/pkg/util/flagext" + util_log "github.com/cortexproject/cortex/pkg/util/log" "github.com/cortexproject/cortex/pkg/util/services" ) @@ -54,55 +54,15 @@ const ( // ringAutoForgetUnhealthyPeriods is how many consecutive timeout periods an unhealthy instance // in the ring will be automatically removed. ringAutoForgetUnhealthyPeriods = 5 - - statusPage = ` - - - Cortex Alertmanager Status - -

Cortex Alertmanager Status

-

Node

-
-
Name
{{.self.Name}}
-
Addr
{{.self.Addr}}
-
Port
{{.self.Port}}
-
-

Members

- {{ with .members }} - - - {{ range . }} - - {{ end }} -
NameAddr
{{ .Name }}{{ .Addr }}
- {{ else }} -

No peers

- {{ end }} - - -` ) var ( - statusTemplate *template.Template - errInvalidExternalURL = errors.New("the configured external URL is invalid: should not end with /") errShardingLegacyStorage = errors.New("deprecated -alertmanager.storage.* not supported with -alertmanager.sharding-enabled, use -alertmanager-storage.*") errShardingUnsupportedStorage = errors.New("the configured alertmanager storage backend is not supported when sharding is enabled") errZoneAwarenessEnabledWithoutZoneInfo = errors.New("the configured alertmanager has zone awareness enabled but zone is not set") ) -func init() { - statusTemplate = template.Must(template.New("statusPage").Funcs(map[string]interface{}{ - "state": func(enabled bool) string { - if enabled { - return "enabled" - } - return "disabled" - }, - }).Parse(statusPage)) -} - // MultitenantAlertmanagerConfig is the configuration for a multitenant Alertmanager. type MultitenantAlertmanagerConfig struct { DataDir string `yaml:"data_dir"` @@ -259,6 +219,17 @@ type Limits interface { // AlertmanagerMaxTemplateSize returns max size of individual template. 0 = no limit. AlertmanagerMaxTemplateSize(tenant string) int + + // AlertmanagerMaxDispatcherAggregationGroups returns maximum number of aggregation groups in Alertmanager's dispatcher that a tenant can have. + // Each aggregation group consumes single goroutine. 0 = unlimited. + AlertmanagerMaxDispatcherAggregationGroups(t string) int + + // AlertmanagerMaxAlertsCount returns max number of alerts that tenant can have active at the same time. 0 = no limit. + AlertmanagerMaxAlertsCount(tenant string) int + + // AlertmanagerMaxAlertsSizeBytes returns total max size of alerts that tenant can have active at the same time. 0 = no limit. + // Size of the alert is computed from alert labels, annotations and generator URL. + AlertmanagerMaxAlertsSizeBytes(tenant string) int } // A MultitenantAlertmanager manages Alertmanager instances for multiple @@ -364,6 +335,8 @@ func NewMultitenantAlertmanager(cfg *MultitenantAlertmanagerConfig, store alerts var ringStore kv.Client if cfg.ShardingEnabled { + util_log.WarnExperimentalUse("Alertmanager sharding") + ringStore, err = kv.NewClient( cfg.ShardingRing.KVStore, ring.GetCodec(), @@ -1072,14 +1045,6 @@ func (am *MultitenantAlertmanager) alertmanagerFromFallbackConfig(userID string) return am.alertmanagers[userID], nil } -// GetStatusHandler returns the status handler for this multi-tenant -// alertmanager. -func (am *MultitenantAlertmanager) GetStatusHandler() StatusHandler { - return StatusHandler{ - am: am, - } -} - // ReplicateStateForUser attempts to replicate a partial state sent by an alertmanager to its other replicas through the ring. func (am *MultitenantAlertmanager) ReplicateStateForUser(ctx context.Context, userID string, part *clusterpb.Part) error { level.Debug(am.logger).Log("msg", "message received for replication", "user", userID, "key", part.Key) @@ -1115,7 +1080,6 @@ func (am *MultitenantAlertmanager) ReplicateStateForUser(ctx context.Context, us // ReadFullStateForUser attempts to read the full state from each replica for user. Note that it will try to obtain and return // state from all replicas, but will consider it a success if state is obtained from at least one replica. func (am *MultitenantAlertmanager) ReadFullStateForUser(ctx context.Context, userID string) ([]*clusterpb.FullState, error) { - // Only get the set of replicas which contain the specified user. key := shardByUser(userID) replicationSet, err := am.ring.Get(key, RingOp, nil, nil, nil) @@ -1314,19 +1278,6 @@ func (am *MultitenantAlertmanager) ReadState(ctx context.Context, req *alertmana }, nil } -// StatusHandler shows the status of the alertmanager. -type StatusHandler struct { - am *MultitenantAlertmanager -} - -// ServeHTTP serves the status of the alertmanager. -func (s StatusHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) { - err := statusTemplate.Execute(w, s.am.peer.Info()) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } -} - // validateTemplateFilename validated the template filename and returns error if it's not valid. // The validation done in this function is a first fence to avoid having a tenant submitting // a config which may escape the per-tenant data directory on disk. diff --git a/vendor/github.com/cortexproject/cortex/pkg/api/api.go b/vendor/github.com/cortexproject/cortex/pkg/api/api.go index 7410906e17ac..8459049b4feb 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/api/api.go +++ b/vendor/github.com/cortexproject/cortex/pkg/api/api.go @@ -41,6 +41,7 @@ import ( // DistributorPushWrapper wraps around a push. It is similar to middleware.Interface. type DistributorPushWrapper func(next push.Func) push.Func +type ConfigHandler func(actualCfg interface{}, defaultCfg interface{}) http.HandlerFunc type Config struct { ResponseCompression bool `yaml:"response_compression_enabled"` @@ -56,6 +57,12 @@ type Config struct { // This allows downstream projects to wrap the distributor push function // and access the deserialized write requests before/after they are pushed. DistributorPushWrapper DistributorPushWrapper `yaml:"-"` + + // The CustomConfigHandler allows for providing a different handler for the + // `/config` endpoint. If this field is set _before_ the API module is + // initialized, the custom config handler will be used instead of + // DefaultConfigHandler. + CustomConfigHandler ConfigHandler `yaml:"-"` } // RegisterFlags adds the flags required to config this to the given FlagSet. @@ -198,7 +205,7 @@ func (a *API) RegisterAPI(httpPathPrefix string, actualCfg interface{}, defaultC a.indexPage.AddLink(SectionAdminEndpoints, "/config", "Current Config (including the default values)") a.indexPage.AddLink(SectionAdminEndpoints, "/config?mode=diff", "Current Config (show only values that differ from the defaults)") - a.RegisterRoute("/config", configHandler(actualCfg, defaultCfg), false, "GET") + a.RegisterRoute("/config", a.cfg.configHandler(actualCfg, defaultCfg), false, "GET") a.RegisterRoute("/", indexHandler(httpPathPrefix, a.indexPage), false, "GET") a.RegisterRoute("/debug/fgprof", fgprof.Handler(), false, "GET") } @@ -344,11 +351,16 @@ func (a *API) RegisterCompactor(c *compactor.Compactor) { a.RegisterRoute("/compactor/ring", http.HandlerFunc(c.RingHandler), false, "GET", "POST") } +type Distributor interface { + querier.Distributor + UserStatsHandler(w http.ResponseWriter, r *http.Request) +} + // RegisterQueryable registers the the default routes associated with the querier // module. func (a *API) RegisterQueryable( queryable storage.SampleAndChunkQueryable, - distributor *distributor.Distributor, + distributor Distributor, ) { // these routes are always registered to the default server a.RegisterRoute("/api/v1/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true, "GET") @@ -363,6 +375,7 @@ func (a *API) RegisterQueryAPI(handler http.Handler) { a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/read"), handler, true, "POST") a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/query"), handler, true, "GET", "POST") a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/query_range"), handler, true, "GET", "POST") + a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/query_exemplars"), handler, true, "GET", "POST") a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/labels"), handler, true, "GET", "POST") a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/label/{name}/values"), handler, true, "GET") a.RegisterRoute(path.Join(a.cfg.PrometheusHTTPPrefix, "/api/v1/series"), handler, true, "GET", "POST", "DELETE") @@ -372,6 +385,7 @@ func (a *API) RegisterQueryAPI(handler http.Handler) { a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/read"), handler, true, "POST") a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/query"), handler, true, "GET", "POST") a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/query_range"), handler, true, "GET", "POST") + a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/query_exemplars"), handler, true, "GET", "POST") a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/labels"), handler, true, "GET", "POST") a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/label/{name}/values"), handler, true, "GET") a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/series"), handler, true, "GET", "POST", "DELETE") diff --git a/vendor/github.com/cortexproject/cortex/pkg/api/handlers.go b/vendor/github.com/cortexproject/cortex/pkg/api/handlers.go index b3fc01ed4b26..79a231c16f40 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/api/handlers.go +++ b/vendor/github.com/cortexproject/cortex/pkg/api/handlers.go @@ -23,7 +23,6 @@ import ( "github.com/weaveworks/common/middleware" "github.com/cortexproject/cortex/pkg/chunk/purger" - "github.com/cortexproject/cortex/pkg/distributor" "github.com/cortexproject/cortex/pkg/querier" "github.com/cortexproject/cortex/pkg/querier/stats" "github.com/cortexproject/cortex/pkg/util" @@ -111,7 +110,14 @@ func indexHandler(httpPathPrefix string, content *IndexPageContent) http.Handler } } -func configHandler(actualCfg interface{}, defaultCfg interface{}) http.HandlerFunc { +func (cfg *Config) configHandler(actualCfg interface{}, defaultCfg interface{}) http.HandlerFunc { + if cfg.CustomConfigHandler != nil { + return cfg.CustomConfigHandler(actualCfg, defaultCfg) + } + return DefaultConfigHandler(actualCfg, defaultCfg) +} + +func DefaultConfigHandler(actualCfg interface{}, defaultCfg interface{}) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var output interface{} switch r.URL.Query().Get("mode") { @@ -151,8 +157,9 @@ func configHandler(actualCfg interface{}, defaultCfg interface{}) http.HandlerFu func NewQuerierHandler( cfg Config, queryable storage.SampleAndChunkQueryable, + exemplarQueryable storage.ExemplarQueryable, engine *promql.Engine, - distributor *distributor.Distributor, + distributor Distributor, tombstonesLoader *purger.TombstonesLoader, reg prometheus.Registerer, logger log.Logger, @@ -187,9 +194,9 @@ func NewQuerierHandler( api := v1.NewAPI( engine, - errorTranslateQueryable{queryable}, // Translate errors to errors expected by API. - nil, // No remote write support. - nil, // No exemplars support. + querier.NewErrorTranslateQueryable(queryable), // Translate errors to errors expected by API. + nil, // No remote write support. + exemplarQueryable, func(context.Context) v1.TargetRetriever { return &querier.DummyTargetRetriever{} }, func(context.Context) v1.AlertmanagerRetriever { return &querier.DummyAlertmanagerRetriever{} }, func() config.Config { return config.Config{} }, @@ -242,6 +249,7 @@ func NewQuerierHandler( router.Path(path.Join(prefix, "/api/v1/read")).Methods("POST").Handler(promRouter) router.Path(path.Join(prefix, "/api/v1/query")).Methods("GET", "POST").Handler(promRouter) router.Path(path.Join(prefix, "/api/v1/query_range")).Methods("GET", "POST").Handler(promRouter) + router.Path(path.Join(prefix, "/api/v1/query_exemplars")).Methods("GET", "POST").Handler(promRouter) router.Path(path.Join(prefix, "/api/v1/labels")).Methods("GET", "POST").Handler(promRouter) router.Path(path.Join(prefix, "/api/v1/label/{name}/values")).Methods("GET").Handler(promRouter) router.Path(path.Join(prefix, "/api/v1/series")).Methods("GET", "POST", "DELETE").Handler(promRouter) @@ -254,6 +262,7 @@ func NewQuerierHandler( router.Path(path.Join(legacyPrefix, "/api/v1/read")).Methods("POST").Handler(legacyPromRouter) router.Path(path.Join(legacyPrefix, "/api/v1/query")).Methods("GET", "POST").Handler(legacyPromRouter) router.Path(path.Join(legacyPrefix, "/api/v1/query_range")).Methods("GET", "POST").Handler(legacyPromRouter) + router.Path(path.Join(legacyPrefix, "/api/v1/query_exemplars")).Methods("GET", "POST").Handler(legacyPromRouter) router.Path(path.Join(legacyPrefix, "/api/v1/labels")).Methods("GET", "POST").Handler(legacyPromRouter) router.Path(path.Join(legacyPrefix, "/api/v1/label/{name}/values")).Methods("GET").Handler(legacyPromRouter) router.Path(path.Join(legacyPrefix, "/api/v1/series")).Methods("GET", "POST", "DELETE").Handler(legacyPromRouter) diff --git a/vendor/github.com/cortexproject/cortex/pkg/chunk/cache/cache.go b/vendor/github.com/cortexproject/cortex/pkg/chunk/cache/cache.go index b6144dbf8fea..d95df970a71f 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/chunk/cache/cache.go +++ b/vendor/github.com/cortexproject/cortex/pkg/chunk/cache/cache.go @@ -99,7 +99,7 @@ func New(cfg Config, reg prometheus.Registerer, logger log.Logger) (Cache, error cfg.Redis.Expiration = cfg.DefaultValidity } cacheName := cfg.Prefix + "redis" - cache := NewRedisCache(cacheName, NewRedisClient(&cfg.Redis), logger) + cache := NewRedisCache(cacheName, NewRedisClient(&cfg.Redis), reg, logger) caches = append(caches, NewBackground(cacheName, cfg.Background, Instrument(cacheName, cache, reg), reg)) } diff --git a/vendor/github.com/cortexproject/cortex/pkg/chunk/cache/redis_cache.go b/vendor/github.com/cortexproject/cortex/pkg/chunk/cache/redis_cache.go index efe1e786e77a..3a88d0ab4713 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/chunk/cache/redis_cache.go +++ b/vendor/github.com/cortexproject/cortex/pkg/chunk/cache/redis_cache.go @@ -5,24 +5,39 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + otlog "github.com/opentracing/opentracing-go/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + instr "github.com/weaveworks/common/instrument" util_log "github.com/cortexproject/cortex/pkg/util/log" + "github.com/cortexproject/cortex/pkg/util/spanlogger" ) // RedisCache type caches chunks in redis type RedisCache struct { - name string - redis *RedisClient - logger log.Logger + name string + redis *RedisClient + logger log.Logger + requestDuration observableVecCollector } // NewRedisCache creates a new RedisCache -func NewRedisCache(name string, redisClient *RedisClient, logger log.Logger) *RedisCache { +func NewRedisCache(name string, redisClient *RedisClient, reg prometheus.Registerer, logger log.Logger) *RedisCache { util_log.WarnExperimentalUse("Redis cache") cache := &RedisCache{ name: name, redis: redisClient, logger: logger, + requestDuration: observableVecCollector{ + v: promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "cortex", + Name: "rediscache_request_duration_seconds", + Help: "Total time spent in seconds doing Redis requests.", + Buckets: prometheus.ExponentialBuckets(0.000016, 4, 8), + ConstLabels: prometheus.Labels{"name": name}, + }, []string{"method", "status_code"}), + }, } if err := cache.redis.Ping(context.Background()); err != nil { level.Error(logger).Log("msg", "error connecting to redis", "name", name, "err", err) @@ -30,23 +45,51 @@ func NewRedisCache(name string, redisClient *RedisClient, logger log.Logger) *Re return cache } +func redisStatusCode(err error) string { + // TODO: Figure out if there are more error types returned by Redis + switch err { + case nil: + return "200" + default: + return "500" + } +} + // Fetch gets keys from the cache. The keys that are found must be in the order of the keys requested. func (c *RedisCache) Fetch(ctx context.Context, keys []string) (found []string, bufs [][]byte, missed []string) { - data, err := c.redis.MGet(ctx, keys) + const method = "RedisCache.MGet" + var items [][]byte + // Run a tracked request, using c.requestDuration to monitor requests. + err := instr.CollectedRequest(ctx, method, c.requestDuration, redisStatusCode, func(ctx context.Context) error { + log, _ := spanlogger.New(ctx, method) + defer log.Finish() + log.LogFields(otlog.Int("keys requested", len(keys))) + + var err error + items, err = c.redis.MGet(ctx, keys) + if err != nil { + log.Error(err) + level.Error(c.logger).Log("msg", "failed to get from redis", "name", c.name, "err", err) + return err + } + + log.LogFields(otlog.Int("keys found", len(items))) + + return nil + }) if err != nil { - level.Error(c.logger).Log("msg", "failed to get from redis", "name", c.name, "err", err) - missed = make([]string, len(keys)) - copy(missed, keys) - return + return found, bufs, keys } + for i, key := range keys { - if data[i] != nil { + if items[i] != nil { found = append(found, key) - bufs = append(bufs, data[i]) + bufs = append(bufs, items[i]) } else { missed = append(missed, key) } } + return } diff --git a/vendor/github.com/cortexproject/cortex/pkg/chunk/gcp/gcs_object_client.go b/vendor/github.com/cortexproject/cortex/pkg/chunk/gcp/gcs_object_client.go index 0c956e446adf..8a064f8958c1 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/chunk/gcp/gcs_object_client.go +++ b/vendor/github.com/cortexproject/cortex/pkg/chunk/gcp/gcs_object_client.go @@ -8,6 +8,7 @@ import ( "cloud.google.com/go/storage" "google.golang.org/api/iterator" + "google.golang.org/api/option" "github.com/cortexproject/cortex/pkg/chunk" "github.com/cortexproject/cortex/pkg/chunk/util" @@ -21,9 +22,10 @@ type GCSObjectClient struct { // GCSConfig is config for the GCS Chunk Client. type GCSConfig struct { - BucketName string `yaml:"bucket_name"` - ChunkBufferSize int `yaml:"chunk_buffer_size"` - RequestTimeout time.Duration `yaml:"request_timeout"` + BucketName string `yaml:"bucket_name"` + ChunkBufferSize int `yaml:"chunk_buffer_size"` + RequestTimeout time.Duration `yaml:"request_timeout"` + EnableOpenCensus bool `yaml:"enable_opencensus"` } // RegisterFlags registers flags. @@ -36,16 +38,22 @@ func (cfg *GCSConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { f.StringVar(&cfg.BucketName, prefix+"gcs.bucketname", "", "Name of GCS bucket. Please refer to https://cloud.google.com/docs/authentication/production for more information about how to configure authentication.") f.IntVar(&cfg.ChunkBufferSize, prefix+"gcs.chunk-buffer-size", 0, "The size of the buffer that GCS client for each PUT request. 0 to disable buffering.") f.DurationVar(&cfg.RequestTimeout, prefix+"gcs.request-timeout", 0, "The duration after which the requests to GCS should be timed out.") + f.BoolVar(&cfg.EnableOpenCensus, prefix+"gcs.enable-opencensus", true, "Enabled OpenCensus (OC) instrumentation for all requests.") } // NewGCSObjectClient makes a new chunk.Client that writes chunks to GCS. func NewGCSObjectClient(ctx context.Context, cfg GCSConfig) (*GCSObjectClient, error) { - option, err := gcsInstrumentation(ctx, storage.ScopeReadWrite) + var opts []option.ClientOption + instrumentation, err := gcsInstrumentation(ctx, storage.ScopeReadWrite) if err != nil { return nil, err } + opts = append(opts, instrumentation) + if !cfg.EnableOpenCensus { + opts = append(opts, option.WithTelemetryDisabled()) + } - client, err := storage.NewClient(ctx, option) + client, err := storage.NewClient(ctx, opts...) if err != nil { return nil, err } @@ -85,7 +93,6 @@ func (s *GCSObjectClient) GetObject(ctx context.Context, objectKey string) (io.R func (s *GCSObjectClient) getObject(ctx context.Context, objectKey string) (rc io.ReadCloser, err error) { reader, err := s.bucket.Object(objectKey).NewReader(ctx) - if err != nil { if err == storage.ErrObjectNotExist { return nil, chunk.ErrStorageObjectNotFound @@ -165,7 +172,6 @@ func (s *GCSObjectClient) List(ctx context.Context, prefix, delimiter string) ([ // key does not exist a generic chunk.ErrStorageObjectNotFound error is returned. func (s *GCSObjectClient) DeleteObject(ctx context.Context, objectKey string) error { err := s.bucket.Object(objectKey).Delete(ctx) - if err != nil { if err == storage.ErrObjectNotExist { return chunk.ErrStorageObjectNotFound diff --git a/vendor/github.com/cortexproject/cortex/pkg/chunk/storage/factory.go b/vendor/github.com/cortexproject/cortex/pkg/chunk/storage/factory.go index 73c96ed2ed6b..20caae7462b7 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/chunk/storage/factory.go +++ b/vendor/github.com/cortexproject/cortex/pkg/chunk/storage/factory.go @@ -111,7 +111,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { cfg.Swift.RegisterFlags(f) cfg.GrpcConfig.RegisterFlags(f) - f.StringVar(&cfg.Engine, "store.engine", "chunks", "The storage engine to use: chunks or blocks.") + f.StringVar(&cfg.Engine, "store.engine", "chunks", "The storage engine to use: chunks (deprecated) or blocks.") cfg.IndexQueriesCacheConfig.RegisterFlagsWithPrefix("store.index-cache-read.", "Cache config for index entry reading. ", f) f.DurationVar(&cfg.IndexCacheValidity, "store.index-cache-validity", 5*time.Minute, "Cache validity for active index entries. Should be no higher than -ingester.max-chunk-idle.") } diff --git a/vendor/github.com/cortexproject/cortex/pkg/compactor/compactor.go b/vendor/github.com/cortexproject/cortex/pkg/compactor/compactor.go index 51952688cb40..0af2088bd59b 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/compactor/compactor.go +++ b/vendor/github.com/cortexproject/cortex/pkg/compactor/compactor.go @@ -393,14 +393,18 @@ func (c *Compactor) starting(ctx context.Context) error { // users scanner depends on the ring (to check whether an user belongs // to this shard or not). level.Info(c.logger).Log("msg", "waiting until compactor is ACTIVE in the ring") - if err := ring.WaitInstanceState(ctx, c.ring, c.ringLifecycler.ID, ring.ACTIVE); err != nil { + + ctxWithTimeout, cancel := context.WithTimeout(ctx, c.compactorCfg.ShardingRing.WaitActiveInstanceTimeout) + defer cancel() + if err := ring.WaitInstanceState(ctxWithTimeout, c.ring, c.ringLifecycler.ID, ring.ACTIVE); err != nil { + level.Error(c.logger).Log("msg", "compactor failed to become ACTIVE in the ring", "err", err) return err } level.Info(c.logger).Log("msg", "compactor is ACTIVE in the ring") // In the event of a cluster cold start or scale up of 2+ compactor instances at the same // time, we may end up in a situation where each new compactor instance starts at a slightly - // different time and thus each one starts with on a different state of the ring. It's better + // different time and thus each one starts with a different state of the ring. It's better // to just wait the ring stability for a short time. if c.compactorCfg.ShardingRing.WaitStabilityMinDuration > 0 { minWaiting := c.compactorCfg.ShardingRing.WaitStabilityMinDuration @@ -408,9 +412,9 @@ func (c *Compactor) starting(ctx context.Context) error { level.Info(c.logger).Log("msg", "waiting until compactor ring topology is stable", "min_waiting", minWaiting.String(), "max_waiting", maxWaiting.String()) if err := ring.WaitRingStability(ctx, c.ring, RingOp, minWaiting, maxWaiting); err != nil { - level.Warn(c.logger).Log("msg", "compactor is ring topology is not stable after the max waiting time, proceeding anyway") + level.Warn(c.logger).Log("msg", "compactor ring topology is not stable after the max waiting time, proceeding anyway") } else { - level.Info(c.logger).Log("msg", "compactor is ring topology is stable") + level.Info(c.logger).Log("msg", "compactor ring topology is stable") } } } diff --git a/vendor/github.com/cortexproject/cortex/pkg/compactor/compactor_ring.go b/vendor/github.com/cortexproject/cortex/pkg/compactor/compactor_ring.go index d10f675f5e00..285a1fa6bc73 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/compactor/compactor_ring.go +++ b/vendor/github.com/cortexproject/cortex/pkg/compactor/compactor_ring.go @@ -34,6 +34,10 @@ type RingConfig struct { // Injected internally ListenPort int `yaml:"-"` + + WaitActiveInstanceTimeout time.Duration `yaml:"wait_active_instance_timeout"` + + ObservePeriod time.Duration `yaml:"-"` } // RegisterFlags adds the flags required to config this to the given FlagSet @@ -46,12 +50,12 @@ func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { // Ring flags cfg.KVStore.RegisterFlagsWithPrefix("compactor.ring.", "collectors/", f) - f.DurationVar(&cfg.HeartbeatPeriod, "compactor.ring.heartbeat-period", 5*time.Second, "Period at which to heartbeat to the ring.") - f.DurationVar(&cfg.HeartbeatTimeout, "compactor.ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which compactors are considered unhealthy within the ring.") + f.DurationVar(&cfg.HeartbeatPeriod, "compactor.ring.heartbeat-period", 5*time.Second, "Period at which to heartbeat to the ring. 0 = disabled.") + f.DurationVar(&cfg.HeartbeatTimeout, "compactor.ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which compactors are considered unhealthy within the ring. 0 = never (timeout disabled).") // Wait stability flags. f.DurationVar(&cfg.WaitStabilityMinDuration, "compactor.ring.wait-stability-min-duration", time.Minute, "Minimum time to wait for ring stability at startup. 0 to disable.") - f.DurationVar(&cfg.WaitStabilityMaxDuration, "compactor.ring.wait-stability-max-duration", 5*time.Minute, "Maximum time to wait for ring stability at startup. If the compactor ring keep changing after this period of time, the compactor will start anyway.") + f.DurationVar(&cfg.WaitStabilityMaxDuration, "compactor.ring.wait-stability-max-duration", 5*time.Minute, "Maximum time to wait for ring stability at startup. If the compactor ring keeps changing after this period of time, the compactor will start anyway.") // Instance flags cfg.InstanceInterfaceNames = []string{"eth0", "en0"} @@ -59,6 +63,9 @@ func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { f.StringVar(&cfg.InstanceAddr, "compactor.ring.instance-addr", "", "IP address to advertise in the ring.") f.IntVar(&cfg.InstancePort, "compactor.ring.instance-port", 0, "Port to advertise in the ring (defaults to server.grpc-listen-port).") f.StringVar(&cfg.InstanceID, "compactor.ring.instance-id", hostname, "Instance ID to register in the ring.") + + // Timeout durations + f.DurationVar(&cfg.WaitActiveInstanceTimeout, "compactor.ring.wait-active-instance-timeout", 10*time.Minute, "Timeout for waiting on compactor to become ACTIVE in the ring.") } // ToLifecyclerConfig returns a LifecyclerConfig based on the compactor @@ -87,7 +94,7 @@ func (cfg *RingConfig) ToLifecyclerConfig() ring.LifecyclerConfig { lc.InfNames = cfg.InstanceInterfaceNames lc.UnregisterOnShutdown = true lc.HeartbeatPeriod = cfg.HeartbeatPeriod - lc.ObservePeriod = 0 + lc.ObservePeriod = cfg.ObservePeriod lc.JoinAfter = 0 lc.MinReadyDuration = 0 lc.FinalSleep = 0 diff --git a/vendor/github.com/cortexproject/cortex/pkg/cortex/cortex.go b/vendor/github.com/cortexproject/cortex/pkg/cortex/cortex.go index 07d62929658c..76fb18e0f0aa 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/cortex/cortex.go +++ b/vendor/github.com/cortexproject/cortex/pkg/cortex/cortex.go @@ -170,7 +170,7 @@ func (c *Config) RegisterFlags(f *flag.FlagSet) { c.Alertmanager.RegisterFlags(f) c.AlertmanagerStorage.RegisterFlags(f) c.RuntimeConfig.RegisterFlags(f) - c.MemberlistKV.RegisterFlags(f, "") + c.MemberlistKV.RegisterFlags(f) c.QueryScheduler.RegisterFlags(f) // These don't seem to have a home. @@ -326,6 +326,7 @@ type Cortex struct { Purger *purger.Purger TombstonesLoader *purger.TombstonesLoader QuerierQueryable prom_storage.SampleAndChunkQueryable + ExemplarQueryable prom_storage.ExemplarQueryable QuerierEngine *promql.Engine QueryFrontendTripperware queryrange.Tripperware diff --git a/vendor/github.com/cortexproject/cortex/pkg/cortex/modules.go b/vendor/github.com/cortexproject/cortex/pkg/cortex/modules.go index 5c36059e2e64..488e9aadddd3 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/cortex/modules.go +++ b/vendor/github.com/cortexproject/cortex/pkg/cortex/modules.go @@ -222,7 +222,7 @@ func (t *Cortex) initQueryable() (serv services.Service, err error) { querierRegisterer := prometheus.WrapRegistererWith(prometheus.Labels{"engine": "querier"}, prometheus.DefaultRegisterer) // Create a querier queryable and PromQL engine - t.QuerierQueryable, t.QuerierEngine = querier.New(t.Cfg.Querier, t.Overrides, t.Distributor, t.StoreQueryables, t.TombstonesLoader, querierRegisterer, util_log.Logger) + t.QuerierQueryable, t.ExemplarQueryable, t.QuerierEngine = querier.New(t.Cfg.Querier, t.Overrides, t.Distributor, t.StoreQueryables, t.TombstonesLoader, querierRegisterer, util_log.Logger) // Register the default endpoints that are always enabled for the querier module t.API.RegisterQueryable(t.QuerierQueryable, t.Distributor) @@ -298,6 +298,7 @@ func (t *Cortex) initQuerier() (serv services.Service, err error) { internalQuerierRouter := api.NewQuerierHandler( t.Cfg.API, t.QuerierQueryable, + t.ExemplarQueryable, t.QuerierEngine, t.Distributor, t.TombstonesLoader, @@ -637,7 +638,7 @@ func (t *Cortex) initRulerStorage() (serv services.Service, err error) { // unfortunately there is no way to generate a "default" config and compare default against actual // to determine if it's unconfigured. the following check, however, correctly tests this. // Single binary integration tests will break if this ever drifts - if t.Cfg.isModuleEnabled(All) && t.Cfg.Ruler.StoreConfig.IsDefaults() { + if t.Cfg.isModuleEnabled(All) && t.Cfg.Ruler.StoreConfig.IsDefaults() && t.Cfg.RulerStorage.IsDefaults() { level.Info(util_log.Logger).Log("msg", "Ruler storage is not configured in single binary mode and will not be started.") return } @@ -659,9 +660,9 @@ func (t *Cortex) initRuler() (serv services.Service, err error) { t.Cfg.Ruler.Ring.ListenPort = t.Cfg.Server.GRPCListenPort rulerRegisterer := prometheus.WrapRegistererWith(prometheus.Labels{"engine": "ruler"}, prometheus.DefaultRegisterer) // TODO: Consider wrapping logger to differentiate from querier module logger - queryable, engine := querier.New(t.Cfg.Querier, t.Overrides, t.Distributor, t.StoreQueryables, t.TombstonesLoader, rulerRegisterer, util_log.Logger) + queryable, _, engine := querier.New(t.Cfg.Querier, t.Overrides, t.Distributor, t.StoreQueryables, t.TombstonesLoader, rulerRegisterer, util_log.Logger) - managerFactory := ruler.DefaultTenantManagerFactory(t.Cfg.Ruler, t.Distributor, queryable, engine, t.Overrides) + managerFactory := ruler.DefaultTenantManagerFactory(t.Cfg.Ruler, t.Distributor, queryable, engine, t.Overrides, prometheus.DefaultRegisterer) manager, err := ruler.NewDefaultMultiTenantManager(t.Cfg.Ruler, managerFactory, prometheus.DefaultRegisterer, util_log.Logger) if err != nil { return nil, err diff --git a/vendor/github.com/cortexproject/cortex/pkg/cortex/runtime_config.go b/vendor/github.com/cortexproject/cortex/pkg/cortex/runtime_config.go index 33f6f41f8b29..150c25727b27 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/cortex/runtime_config.go +++ b/vendor/github.com/cortexproject/cortex/pkg/cortex/runtime_config.go @@ -28,7 +28,7 @@ type runtimeConfigValues struct { IngesterChunkStreaming *bool `yaml:"ingester_stream_chunks_when_using_blocks"` - IngesterLimits ingester.InstanceLimits `yaml:"ingester_limits"` + IngesterLimits *ingester.InstanceLimits `yaml:"ingester_limits"` } // runtimeConfigTenantLimits provides per-tenant limit overrides based on a runtimeconfig.Manager @@ -134,7 +134,7 @@ func ingesterInstanceLimits(manager *runtimeconfig.Manager) func() *ingester.Ins return func() *ingester.InstanceLimits { val := manager.GetConfig() if cfg, ok := val.(*runtimeConfigValues); ok && cfg != nil { - return &cfg.IngesterLimits + return cfg.IngesterLimits } return nil } diff --git a/vendor/github.com/cortexproject/cortex/pkg/cortexpb/compat.go b/vendor/github.com/cortexproject/cortex/pkg/cortexpb/compat.go index 4dc2b8804b81..9f2c655e2dc9 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/cortexpb/compat.go +++ b/vendor/github.com/cortexproject/cortex/pkg/cortexpb/compat.go @@ -12,6 +12,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/pkg/exemplar" "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/textparse" @@ -116,6 +117,30 @@ func FromMetricsToLabelAdapters(metric model.Metric) []LabelAdapter { return result } +func FromExemplarsToExemplarProtos(es []exemplar.Exemplar) []Exemplar { + result := make([]Exemplar, 0, len(es)) + for _, e := range es { + result = append(result, Exemplar{ + Labels: FromLabelsToLabelAdapters(e.Labels), + Value: e.Value, + TimestampMs: e.Ts, + }) + } + return result +} + +func FromExemplarProtosToExemplars(es []Exemplar) []exemplar.Exemplar { + result := make([]exemplar.Exemplar, 0, len(es)) + for _, e := range es { + result = append(result, exemplar.Exemplar{ + Labels: FromLabelAdaptersToLabels(e.Labels), + Value: e.Value, + Ts: e.TimestampMs, + }) + } + return result +} + type byLabel []LabelAdapter func (s byLabel) Len() int { return len(s) } diff --git a/vendor/github.com/cortexproject/cortex/pkg/distributor/distributor.go b/vendor/github.com/cortexproject/cortex/pkg/distributor/distributor.go index 5cdb0244fb9d..ca9039dc5422 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/distributor/distributor.go +++ b/vendor/github.com/cortexproject/cortex/pkg/distributor/distributor.go @@ -242,7 +242,7 @@ func New(cfg Config, clientConfig ingester_client.Config, limits *validation.Ove queryDuration: instrument.NewHistogramCollector(promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{ Namespace: "cortex", Name: "distributor_query_duration_seconds", - Help: "Time spent executing expression queries.", + Help: "Time spent executing expression and exemplar queries.", Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 20, 30}, }, []string{"method", "status_code"})), receivedSamples: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ diff --git a/vendor/github.com/cortexproject/cortex/pkg/distributor/distributor_ring.go b/vendor/github.com/cortexproject/cortex/pkg/distributor/distributor_ring.go index ee96a7d37cd9..3655aa99854f 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/distributor/distributor_ring.go +++ b/vendor/github.com/cortexproject/cortex/pkg/distributor/distributor_ring.go @@ -42,8 +42,8 @@ func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { // Ring flags cfg.KVStore.RegisterFlagsWithPrefix("distributor.ring.", "collectors/", f) - f.DurationVar(&cfg.HeartbeatPeriod, "distributor.ring.heartbeat-period", 5*time.Second, "Period at which to heartbeat to the ring.") - f.DurationVar(&cfg.HeartbeatTimeout, "distributor.ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which distributors are considered unhealthy within the ring.") + f.DurationVar(&cfg.HeartbeatPeriod, "distributor.ring.heartbeat-period", 5*time.Second, "Period at which to heartbeat to the ring. 0 = disabled.") + f.DurationVar(&cfg.HeartbeatTimeout, "distributor.ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which distributors are considered unhealthy within the ring. 0 = never (timeout disabled).") // Instance flags cfg.InstanceInterfaceNames = []string{"eth0", "en0"} diff --git a/vendor/github.com/cortexproject/cortex/pkg/distributor/ha_tracker.go b/vendor/github.com/cortexproject/cortex/pkg/distributor/ha_tracker.go index a998b7f5f2cd..51d1b5f37059 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/distributor/ha_tracker.go +++ b/vendor/github.com/cortexproject/cortex/pkg/distributor/ha_tracker.go @@ -107,8 +107,8 @@ type haTracker struct { limits haTrackerLimits electedLock sync.RWMutex - elected map[string]ReplicaDesc // Replicas we are accepting samples from. Key = "user/cluster". - clusters map[string]int // Number of clusters with elected replicas that a single user has. Key = user. + elected map[string]ReplicaDesc // Replicas we are accepting samples from. Key = "user/cluster". + clusters map[string]map[string]struct{} // Known clusters with elected replicas per user. First key = user, second key = cluster name. electedReplicaChanges *prometheus.CounterVec electedReplicaTimestamp *prometheus.GaugeVec @@ -118,7 +118,7 @@ type haTracker struct { cleanupRuns prometheus.Counter replicasMarkedForDeletion prometheus.Counter deletedReplicas prometheus.Counter - markingOrDeletionsFailed prometheus.Counter + markingForDeletionsFailed prometheus.Counter } // NewClusterTracker returns a new HA cluster tracker using either Consul @@ -135,7 +135,7 @@ func newHATracker(cfg HATrackerConfig, limits haTrackerLimits, reg prometheus.Re updateTimeoutJitter: jitter, limits: limits, elected: map[string]ReplicaDesc{}, - clusters: map[string]int{}, + clusters: map[string]map[string]struct{}{}, electedReplicaChanges: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ Name: "cortex_ha_tracker_elected_replica_changes_total", @@ -167,7 +167,7 @@ func newHATracker(cfg HATrackerConfig, limits haTrackerLimits, reg prometheus.Re Name: "cortex_ha_tracker_replicas_cleanup_deleted_total", Help: "Number of elected replicas deleted from KV store.", }), - markingOrDeletionsFailed: promauto.With(reg).NewCounter(prometheus.CounterOpts{ + markingForDeletionsFailed: promauto.With(reg).NewCounter(prometheus.CounterOpts{ Name: "cortex_ha_tracker_replicas_cleanup_delete_failed_total", Help: "Number of elected replicas that failed to be marked for deletion, or deleted.", }), @@ -226,6 +226,14 @@ func (c *haTracker) loop(ctx context.Context) error { delete(c.elected, key) c.electedReplicaChanges.DeleteLabelValues(user, cluster) c.electedReplicaTimestamp.DeleteLabelValues(user, cluster) + + userClusters := c.clusters[user] + if userClusters != nil { + delete(userClusters, cluster) + if len(userClusters) == 0 { + delete(c.clusters, user) + } + } return true } @@ -234,7 +242,10 @@ func (c *haTracker) loop(ctx context.Context) error { c.electedReplicaChanges.WithLabelValues(user, cluster).Inc() } if !exists { - c.clusters[user]++ + if c.clusters[user] == nil { + c.clusters[user] = map[string]struct{}{} + } + c.clusters[user][cluster] = struct{}{} } c.elected[key] = *replica c.electedReplicaTimestamp.WithLabelValues(user, cluster).Set(float64(replica.ReceivedAt / 1000)) @@ -312,7 +323,7 @@ func (c *haTracker) cleanupOldReplicas(ctx context.Context, deadline time.Time) err = c.client.Delete(ctx, key) if err != nil { level.Error(c.logger).Log("msg", "cleanup: failed to delete old replica", "key", key, "err", err) - c.markingOrDeletionsFailed.Inc() + c.markingForDeletionsFailed.Inc() } else { level.Info(c.logger).Log("msg", "cleanup: deleted old replica", "key", key) c.deletedReplicas.Inc() @@ -333,7 +344,7 @@ func (c *haTracker) cleanupOldReplicas(ctx context.Context, deadline time.Time) }) if err != nil { - c.markingOrDeletionsFailed.Inc() + c.markingForDeletionsFailed.Inc() level.Error(c.logger).Log("msg", "cleanup: failed to mark replica as deleted", "key", key, "err", err) } else { c.replicasMarkedForDeletion.Inc() @@ -359,7 +370,7 @@ func (c *haTracker) checkReplica(ctx context.Context, userID, cluster, replica s c.electedLock.RLock() entry, ok := c.elected[key] - clusters := c.clusters[userID] + clusters := len(c.clusters[userID]) c.electedLock.RUnlock() if ok && now.Sub(timestamp.Time(entry.ReceivedAt)) < c.cfg.UpdateTimeout+c.updateTimeoutJitter { diff --git a/vendor/github.com/cortexproject/cortex/pkg/distributor/query.go b/vendor/github.com/cortexproject/cortex/pkg/distributor/query.go index 5e36aec06f2d..8619a0712586 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/distributor/query.go +++ b/vendor/github.com/cortexproject/cortex/pkg/distributor/query.go @@ -2,15 +2,14 @@ package distributor import ( "context" - "fmt" "io" + "sort" "time" "github.com/opentracing/opentracing-go" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/pkg/labels" "github.com/weaveworks/common/instrument" - "go.uber.org/atomic" "github.com/cortexproject/cortex/pkg/cortexpb" ingester_client "github.com/cortexproject/cortex/pkg/ingester/client" @@ -23,10 +22,6 @@ import ( "github.com/cortexproject/cortex/pkg/util/validation" ) -var ( - errMaxChunksPerQueryLimit = "the query hit the max number of chunks limit while fetching chunks from ingesters for %s (limit: %d)" -) - // Query multiple ingesters and returns a Matrix of samples. func (d *Distributor) Query(ctx context.Context, from, to model.Time, matchers ...*labels.Matcher) (model.Matrix, error) { var matrix model.Matrix @@ -54,15 +49,37 @@ func (d *Distributor) Query(ctx context.Context, from, to model.Time, matchers . return matrix, err } -// QueryStream multiple ingesters via the streaming interface and returns big ol' set of chunks. -func (d *Distributor) QueryStream(ctx context.Context, from, to model.Time, matchers ...*labels.Matcher) (*ingester_client.QueryStreamResponse, error) { - var result *ingester_client.QueryStreamResponse - err := instrument.CollectedRequest(ctx, "Distributor.QueryStream", d.queryDuration, instrument.ErrorCode, func(ctx context.Context) error { - userID, err := tenant.TenantID(ctx) +func (d *Distributor) QueryExemplars(ctx context.Context, from, to model.Time, matchers ...[]*labels.Matcher) (*ingester_client.ExemplarQueryResponse, error) { + var result *ingester_client.ExemplarQueryResponse + err := instrument.CollectedRequest(ctx, "Distributor.QueryExemplars", d.queryDuration, instrument.ErrorCode, func(ctx context.Context) error { + req, err := ingester_client.ToExemplarQueryRequest(from, to, matchers...) + if err != nil { + return err + } + + // We ask for all ingesters without passing matchers because exemplar queries take in an array of array of label matchers. + replicationSet, err := d.GetIngestersForQuery(ctx, nil) if err != nil { return err } + result, err = d.queryIngestersExemplars(ctx, replicationSet, req) + if err != nil { + return err + } + + if s := opentracing.SpanFromContext(ctx); s != nil { + s.LogKV("series", len(result.Timeseries)) + } + return nil + }) + return result, err +} + +// QueryStream multiple ingesters via the streaming interface and returns big ol' set of chunks. +func (d *Distributor) QueryStream(ctx context.Context, from, to model.Time, matchers ...*labels.Matcher) (*ingester_client.QueryStreamResponse, error) { + var result *ingester_client.QueryStreamResponse + err := instrument.CollectedRequest(ctx, "Distributor.QueryStream", d.queryDuration, instrument.ErrorCode, func(ctx context.Context) error { req, err := ingester_client.ToQueryRequest(from, to, matchers) if err != nil { return err @@ -73,7 +90,7 @@ func (d *Distributor) QueryStream(ctx context.Context, from, to model.Time, matc return err } - result, err = d.queryIngesterStream(ctx, userID, replicationSet, req) + result, err = d.queryIngesterStream(ctx, replicationSet, req) if err != nil { return err } @@ -106,7 +123,7 @@ func (d *Distributor) GetIngestersForQuery(ctx context.Context, matchers ...*lab } // If "shard by all labels" is disabled, we can get ingesters by metricName if exists. - if !d.cfg.ShardByAllLabels { + if !d.cfg.ShardByAllLabels && len(matchers) > 0 { metricNameMatcher, _, ok := extract.MetricNameMatcherFromMatchers(matchers) if ok && metricNameMatcher.Type == labels.MatchEqual { @@ -185,11 +202,85 @@ func (d *Distributor) queryIngesters(ctx context.Context, replicationSet ring.Re return result, nil } +// mergeExemplarSets merges and dedupes two sets of already sorted exemplar pairs. +// Both a and b should be lists of exemplars from the same series. +// Defined here instead of pkg/util to avoid a import cycle. +func mergeExemplarSets(a, b []cortexpb.Exemplar) []cortexpb.Exemplar { + result := make([]cortexpb.Exemplar, 0, len(a)+len(b)) + i, j := 0, 0 + for i < len(a) && j < len(b) { + if a[i].TimestampMs < b[j].TimestampMs { + result = append(result, a[i]) + i++ + } else if a[i].TimestampMs > b[j].TimestampMs { + result = append(result, b[j]) + j++ + } else { + result = append(result, a[i]) + i++ + j++ + } + } + // Add the rest of a or b. One of them is empty now. + result = append(result, a[i:]...) + result = append(result, b[j:]...) + return result +} + +// queryIngestersExemplars queries the ingesters for exemplars. +func (d *Distributor) queryIngestersExemplars(ctx context.Context, replicationSet ring.ReplicationSet, req *ingester_client.ExemplarQueryRequest) (*ingester_client.ExemplarQueryResponse, error) { + // Fetch exemplars from multiple ingesters in parallel, using the replicationSet + // to deal with consistency. + results, err := replicationSet.Do(ctx, d.cfg.ExtraQueryDelay, func(ctx context.Context, ing *ring.InstanceDesc) (interface{}, error) { + client, err := d.ingesterPool.GetClientFor(ing.Addr) + if err != nil { + return nil, err + } + + resp, err := client.(ingester_client.IngesterClient).QueryExemplars(ctx, req) + d.ingesterQueries.WithLabelValues(ing.Addr).Inc() + if err != nil { + d.ingesterQueryFailures.WithLabelValues(ing.Addr).Inc() + return nil, err + } + + return resp, nil + }) + if err != nil { + return nil, err + } + + // Merge results from replication set. + var keys []string + exemplarResults := make(map[string]cortexpb.TimeSeries) + for _, result := range results { + r := result.(*ingester_client.ExemplarQueryResponse) + for _, ts := range r.Timeseries { + lbls := cortexpb.FromLabelAdaptersToLabels(ts.Labels).String() + e, ok := exemplarResults[lbls] + if !ok { + exemplarResults[lbls] = ts + keys = append(keys, lbls) + } + // Merge in any missing values from another ingesters exemplars for this series. + e.Exemplars = mergeExemplarSets(e.Exemplars, ts.Exemplars) + } + } + + // Query results from each ingester were sorted, but are not necessarily still sorted after merging. + sort.Strings(keys) + + result := make([]cortexpb.TimeSeries, len(exemplarResults)) + for i, k := range keys { + result[i] = exemplarResults[k] + } + + return &ingester_client.ExemplarQueryResponse{Timeseries: result}, nil +} + // queryIngesterStream queries the ingesters using the new streaming API. -func (d *Distributor) queryIngesterStream(ctx context.Context, userID string, replicationSet ring.ReplicationSet, req *ingester_client.QueryRequest) (*ingester_client.QueryStreamResponse, error) { +func (d *Distributor) queryIngesterStream(ctx context.Context, replicationSet ring.ReplicationSet, req *ingester_client.QueryRequest) (*ingester_client.QueryStreamResponse, error) { var ( - chunksLimit = d.limits.MaxChunksPerQueryFromIngesters(userID) - chunksCount = atomic.Int32{} queryLimiter = limiter.QueryLimiterFromContextWithFallback(ctx) ) @@ -223,23 +314,23 @@ func (d *Distributor) queryIngesterStream(ctx context.Context, userID string, re } // Enforce the max chunks limits. - if chunksLimit > 0 { - if count := int(chunksCount.Add(int32(resp.ChunksCount()))); count > chunksLimit { - // We expect to be always able to convert the label matchers back to Prometheus ones. - // In case we fail (unexpected) the error will not include the matchers, but the core - // logic doesn't break. - matchers, _ := ingester_client.FromLabelMatchers(req.Matchers) - return nil, validation.LimitError(fmt.Sprintf(errMaxChunksPerQueryLimit, util.LabelMatchersToString(matchers), chunksLimit)) - } + if chunkLimitErr := queryLimiter.AddChunks(resp.ChunksCount()); chunkLimitErr != nil { + return nil, validation.LimitError(chunkLimitErr.Error()) } + for _, series := range resp.Chunkseries { if limitErr := queryLimiter.AddSeries(series.Labels); limitErr != nil { - return nil, limitErr + return nil, validation.LimitError(limitErr.Error()) } } + + if chunkBytesLimitErr := queryLimiter.AddChunkBytes(resp.ChunksSize()); chunkBytesLimitErr != nil { + return nil, validation.LimitError(chunkBytesLimitErr.Error()) + } + for _, series := range resp.Timeseries { if limitErr := queryLimiter.AddSeries(series.Labels); limitErr != nil { - return nil, limitErr + return nil, validation.LimitError(limitErr.Error()) } } diff --git a/vendor/github.com/cortexproject/cortex/pkg/frontend/transport/handler.go b/vendor/github.com/cortexproject/cortex/pkg/frontend/transport/handler.go index 8fcf8e9630e3..435a02274816 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/frontend/transport/handler.go +++ b/vendor/github.com/cortexproject/cortex/pkg/frontend/transport/handler.go @@ -173,6 +173,7 @@ func (f *Handler) reportQueryStats(r *http.Request, queryString url.Values, quer // Log stats. logMessage := append([]interface{}{ "msg", "query stats", + "component", "query-frontend", "method", r.Method, "path", r.URL.Path, "response_time", queryResponseTime, diff --git a/vendor/github.com/cortexproject/cortex/pkg/ingester/client/compat.go b/vendor/github.com/cortexproject/cortex/pkg/ingester/client/compat.go index 78095ff32ecd..7350adcd3b20 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ingester/client/compat.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ingester/client/compat.go @@ -34,6 +34,38 @@ func FromQueryRequest(req *QueryRequest) (model.Time, model.Time, []*labels.Matc return from, to, matchers, nil } +// ToExemplarQueryRequest builds an ExemplarQueryRequest proto. +func ToExemplarQueryRequest(from, to model.Time, matchers ...[]*labels.Matcher) (*ExemplarQueryRequest, error) { + var reqMatchers []*LabelMatchers + for _, m := range matchers { + ms, err := toLabelMatchers(m) + if err != nil { + return nil, err + } + reqMatchers = append(reqMatchers, &LabelMatchers{ms}) + } + + return &ExemplarQueryRequest{ + StartTimestampMs: int64(from), + EndTimestampMs: int64(to), + Matchers: reqMatchers, + }, nil +} + +// FromExemplarQueryRequest unpacks a ExemplarQueryRequest proto. +func FromExemplarQueryRequest(req *ExemplarQueryRequest) (int64, int64, [][]*labels.Matcher, error) { + var result [][]*labels.Matcher + for _, m := range req.Matchers { + matchers, err := FromLabelMatchers(m.Matchers) + if err != nil { + return 0, 0, nil, err + } + result = append(result, matchers) + } + + return req.StartTimestampMs, req.EndTimestampMs, result, nil +} + // ToQueryResponse builds a QueryResponse proto. func ToQueryResponse(matrix model.Matrix) *QueryResponse { resp := &QueryResponse{} diff --git a/vendor/github.com/cortexproject/cortex/pkg/ingester/client/custom.go b/vendor/github.com/cortexproject/cortex/pkg/ingester/client/custom.go index becaab3c0225..e1c0af148c6d 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ingester/client/custom.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ingester/client/custom.go @@ -12,3 +12,18 @@ func (m *QueryStreamResponse) ChunksCount() int { } return count } + +// ChunksSize returns the size of all chunks in the response. +func (m *QueryStreamResponse) ChunksSize() int { + if len(m.Chunkseries) == 0 { + return 0 + } + + size := 0 + for _, entry := range m.Chunkseries { + for _, chunk := range entry.Chunks { + size += chunk.Size() + } + } + return size +} diff --git a/vendor/github.com/cortexproject/cortex/pkg/ingester/client/ingester.pb.go b/vendor/github.com/cortexproject/cortex/pkg/ingester/client/ingester.pb.go index 217007d7b0b2..8949becf7f11 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ingester/client/ingester.pb.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ingester/client/ingester.pb.go @@ -208,6 +208,65 @@ func (m *QueryRequest) GetMatchers() []*LabelMatcher { return nil } +type ExemplarQueryRequest struct { + StartTimestampMs int64 `protobuf:"varint,1,opt,name=start_timestamp_ms,json=startTimestampMs,proto3" json:"start_timestamp_ms,omitempty"` + EndTimestampMs int64 `protobuf:"varint,2,opt,name=end_timestamp_ms,json=endTimestampMs,proto3" json:"end_timestamp_ms,omitempty"` + Matchers []*LabelMatchers `protobuf:"bytes,3,rep,name=matchers,proto3" json:"matchers,omitempty"` +} + +func (m *ExemplarQueryRequest) Reset() { *m = ExemplarQueryRequest{} } +func (*ExemplarQueryRequest) ProtoMessage() {} +func (*ExemplarQueryRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_60f6df4f3586b478, []int{3} +} +func (m *ExemplarQueryRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExemplarQueryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExemplarQueryRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExemplarQueryRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExemplarQueryRequest.Merge(m, src) +} +func (m *ExemplarQueryRequest) XXX_Size() int { + return m.Size() +} +func (m *ExemplarQueryRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ExemplarQueryRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ExemplarQueryRequest proto.InternalMessageInfo + +func (m *ExemplarQueryRequest) GetStartTimestampMs() int64 { + if m != nil { + return m.StartTimestampMs + } + return 0 +} + +func (m *ExemplarQueryRequest) GetEndTimestampMs() int64 { + if m != nil { + return m.EndTimestampMs + } + return 0 +} + +func (m *ExemplarQueryRequest) GetMatchers() []*LabelMatchers { + if m != nil { + return m.Matchers + } + return nil +} + type QueryResponse struct { Timeseries []cortexpb.TimeSeries `protobuf:"bytes,1,rep,name=timeseries,proto3" json:"timeseries"` } @@ -215,7 +274,7 @@ type QueryResponse struct { func (m *QueryResponse) Reset() { *m = QueryResponse{} } func (*QueryResponse) ProtoMessage() {} func (*QueryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{3} + return fileDescriptor_60f6df4f3586b478, []int{4} } func (m *QueryResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -260,7 +319,7 @@ type QueryStreamResponse struct { func (m *QueryStreamResponse) Reset() { *m = QueryStreamResponse{} } func (*QueryStreamResponse) ProtoMessage() {} func (*QueryStreamResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{4} + return fileDescriptor_60f6df4f3586b478, []int{5} } func (m *QueryStreamResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -303,6 +362,49 @@ func (m *QueryStreamResponse) GetTimeseries() []cortexpb.TimeSeries { return nil } +type ExemplarQueryResponse struct { + Timeseries []cortexpb.TimeSeries `protobuf:"bytes,1,rep,name=timeseries,proto3" json:"timeseries"` +} + +func (m *ExemplarQueryResponse) Reset() { *m = ExemplarQueryResponse{} } +func (*ExemplarQueryResponse) ProtoMessage() {} +func (*ExemplarQueryResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_60f6df4f3586b478, []int{6} +} +func (m *ExemplarQueryResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExemplarQueryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExemplarQueryResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExemplarQueryResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExemplarQueryResponse.Merge(m, src) +} +func (m *ExemplarQueryResponse) XXX_Size() int { + return m.Size() +} +func (m *ExemplarQueryResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ExemplarQueryResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ExemplarQueryResponse proto.InternalMessageInfo + +func (m *ExemplarQueryResponse) GetTimeseries() []cortexpb.TimeSeries { + if m != nil { + return m.Timeseries + } + return nil +} + type LabelValuesRequest struct { LabelName string `protobuf:"bytes,1,opt,name=label_name,json=labelName,proto3" json:"label_name,omitempty"` StartTimestampMs int64 `protobuf:"varint,2,opt,name=start_timestamp_ms,json=startTimestampMs,proto3" json:"start_timestamp_ms,omitempty"` @@ -313,7 +415,7 @@ type LabelValuesRequest struct { func (m *LabelValuesRequest) Reset() { *m = LabelValuesRequest{} } func (*LabelValuesRequest) ProtoMessage() {} func (*LabelValuesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{5} + return fileDescriptor_60f6df4f3586b478, []int{7} } func (m *LabelValuesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -377,7 +479,7 @@ type LabelValuesResponse struct { func (m *LabelValuesResponse) Reset() { *m = LabelValuesResponse{} } func (*LabelValuesResponse) ProtoMessage() {} func (*LabelValuesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{6} + return fileDescriptor_60f6df4f3586b478, []int{8} } func (m *LabelValuesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -421,7 +523,7 @@ type LabelNamesRequest struct { func (m *LabelNamesRequest) Reset() { *m = LabelNamesRequest{} } func (*LabelNamesRequest) ProtoMessage() {} func (*LabelNamesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{7} + return fileDescriptor_60f6df4f3586b478, []int{9} } func (m *LabelNamesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -471,7 +573,7 @@ type LabelNamesResponse struct { func (m *LabelNamesResponse) Reset() { *m = LabelNamesResponse{} } func (*LabelNamesResponse) ProtoMessage() {} func (*LabelNamesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{8} + return fileDescriptor_60f6df4f3586b478, []int{10} } func (m *LabelNamesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -513,7 +615,7 @@ type UserStatsRequest struct { func (m *UserStatsRequest) Reset() { *m = UserStatsRequest{} } func (*UserStatsRequest) ProtoMessage() {} func (*UserStatsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{9} + return fileDescriptor_60f6df4f3586b478, []int{11} } func (m *UserStatsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -552,7 +654,7 @@ type UserStatsResponse struct { func (m *UserStatsResponse) Reset() { *m = UserStatsResponse{} } func (*UserStatsResponse) ProtoMessage() {} func (*UserStatsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{10} + return fileDescriptor_60f6df4f3586b478, []int{12} } func (m *UserStatsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -617,7 +719,7 @@ type UserIDStatsResponse struct { func (m *UserIDStatsResponse) Reset() { *m = UserIDStatsResponse{} } func (*UserIDStatsResponse) ProtoMessage() {} func (*UserIDStatsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{11} + return fileDescriptor_60f6df4f3586b478, []int{13} } func (m *UserIDStatsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -667,7 +769,7 @@ type UsersStatsResponse struct { func (m *UsersStatsResponse) Reset() { *m = UsersStatsResponse{} } func (*UsersStatsResponse) ProtoMessage() {} func (*UsersStatsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{12} + return fileDescriptor_60f6df4f3586b478, []int{14} } func (m *UsersStatsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -712,7 +814,7 @@ type MetricsForLabelMatchersRequest struct { func (m *MetricsForLabelMatchersRequest) Reset() { *m = MetricsForLabelMatchersRequest{} } func (*MetricsForLabelMatchersRequest) ProtoMessage() {} func (*MetricsForLabelMatchersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{13} + return fileDescriptor_60f6df4f3586b478, []int{15} } func (m *MetricsForLabelMatchersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -769,7 +871,7 @@ type MetricsForLabelMatchersResponse struct { func (m *MetricsForLabelMatchersResponse) Reset() { *m = MetricsForLabelMatchersResponse{} } func (*MetricsForLabelMatchersResponse) ProtoMessage() {} func (*MetricsForLabelMatchersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{14} + return fileDescriptor_60f6df4f3586b478, []int{16} } func (m *MetricsForLabelMatchersResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -811,7 +913,7 @@ type MetricsMetadataRequest struct { func (m *MetricsMetadataRequest) Reset() { *m = MetricsMetadataRequest{} } func (*MetricsMetadataRequest) ProtoMessage() {} func (*MetricsMetadataRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{15} + return fileDescriptor_60f6df4f3586b478, []int{17} } func (m *MetricsMetadataRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -847,7 +949,7 @@ type MetricsMetadataResponse struct { func (m *MetricsMetadataResponse) Reset() { *m = MetricsMetadataResponse{} } func (*MetricsMetadataResponse) ProtoMessage() {} func (*MetricsMetadataResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{16} + return fileDescriptor_60f6df4f3586b478, []int{18} } func (m *MetricsMetadataResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -893,7 +995,7 @@ type TimeSeriesChunk struct { func (m *TimeSeriesChunk) Reset() { *m = TimeSeriesChunk{} } func (*TimeSeriesChunk) ProtoMessage() {} func (*TimeSeriesChunk) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{17} + return fileDescriptor_60f6df4f3586b478, []int{19} } func (m *TimeSeriesChunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -953,7 +1055,7 @@ type Chunk struct { func (m *Chunk) Reset() { *m = Chunk{} } func (*Chunk) ProtoMessage() {} func (*Chunk) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{18} + return fileDescriptor_60f6df4f3586b478, []int{20} } func (m *Chunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1016,7 +1118,7 @@ type TransferChunksResponse struct { func (m *TransferChunksResponse) Reset() { *m = TransferChunksResponse{} } func (*TransferChunksResponse) ProtoMessage() {} func (*TransferChunksResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{19} + return fileDescriptor_60f6df4f3586b478, []int{21} } func (m *TransferChunksResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1052,7 +1154,7 @@ type LabelMatchers struct { func (m *LabelMatchers) Reset() { *m = LabelMatchers{} } func (*LabelMatchers) ProtoMessage() {} func (*LabelMatchers) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{20} + return fileDescriptor_60f6df4f3586b478, []int{22} } func (m *LabelMatchers) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1097,7 +1199,7 @@ type LabelMatcher struct { func (m *LabelMatcher) Reset() { *m = LabelMatcher{} } func (*LabelMatcher) ProtoMessage() {} func (*LabelMatcher) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{21} + return fileDescriptor_60f6df4f3586b478, []int{23} } func (m *LabelMatcher) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1157,7 +1259,7 @@ type TimeSeriesFile struct { func (m *TimeSeriesFile) Reset() { *m = TimeSeriesFile{} } func (*TimeSeriesFile) ProtoMessage() {} func (*TimeSeriesFile) Descriptor() ([]byte, []int) { - return fileDescriptor_60f6df4f3586b478, []int{22} + return fileDescriptor_60f6df4f3586b478, []int{24} } func (m *TimeSeriesFile) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1219,8 +1321,10 @@ func init() { proto.RegisterType((*ReadRequest)(nil), "cortex.ReadRequest") proto.RegisterType((*ReadResponse)(nil), "cortex.ReadResponse") proto.RegisterType((*QueryRequest)(nil), "cortex.QueryRequest") + proto.RegisterType((*ExemplarQueryRequest)(nil), "cortex.ExemplarQueryRequest") proto.RegisterType((*QueryResponse)(nil), "cortex.QueryResponse") proto.RegisterType((*QueryStreamResponse)(nil), "cortex.QueryStreamResponse") + proto.RegisterType((*ExemplarQueryResponse)(nil), "cortex.ExemplarQueryResponse") proto.RegisterType((*LabelValuesRequest)(nil), "cortex.LabelValuesRequest") proto.RegisterType((*LabelValuesResponse)(nil), "cortex.LabelValuesResponse") proto.RegisterType((*LabelNamesRequest)(nil), "cortex.LabelNamesRequest") @@ -1244,83 +1348,86 @@ func init() { func init() { proto.RegisterFile("ingester.proto", fileDescriptor_60f6df4f3586b478) } var fileDescriptor_60f6df4f3586b478 = []byte{ - // 1211 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4d, 0x6f, 0xdb, 0x46, - 0x13, 0xe6, 0x5a, 0x1f, 0xb1, 0x46, 0xb2, 0x22, 0xaf, 0xf3, 0xda, 0x0a, 0x83, 0x97, 0x4e, 0x09, - 0xa4, 0x15, 0xda, 0x46, 0x4e, 0xdc, 0x0f, 0x24, 0x45, 0x8b, 0x40, 0x4e, 0xec, 0xc4, 0x8d, 0x65, - 0x27, 0xb4, 0xd2, 0x16, 0x05, 0x0a, 0x82, 0x92, 0xd6, 0x32, 0x6b, 0x7e, 0x28, 0xdc, 0x65, 0x51, - 0xdf, 0x0a, 0xf4, 0x07, 0xb4, 0xe8, 0xa9, 0x3f, 0xa1, 0xe7, 0x5e, 0x7a, 0xeb, 0x39, 0x47, 0x1f, - 0x83, 0x1e, 0x82, 0x5a, 0xbe, 0xf4, 0x98, 0xa2, 0x7f, 0xa0, 0xe0, 0x72, 0x49, 0x91, 0xb4, 0xd4, - 0xc6, 0x40, 0x7d, 0xe3, 0xce, 0x3c, 0xf3, 0xec, 0xec, 0xcc, 0xec, 0xcc, 0x12, 0xaa, 0xa6, 0x33, - 0x20, 0x94, 0x11, 0xaf, 0x39, 0xf4, 0x5c, 0xe6, 0xe2, 0x62, 0xcf, 0xf5, 0x18, 0xf9, 0x5a, 0xbe, - 0x3e, 0x30, 0xd9, 0xbe, 0xdf, 0x6d, 0xf6, 0x5c, 0x7b, 0x65, 0xe0, 0x0e, 0xdc, 0x15, 0xae, 0xee, - 0xfa, 0x7b, 0x7c, 0xc5, 0x17, 0xfc, 0x2b, 0x34, 0x93, 0x6f, 0x27, 0xe0, 0x21, 0xc3, 0xd0, 0x73, - 0xbf, 0x24, 0x3d, 0x26, 0x56, 0x2b, 0xc3, 0x83, 0x41, 0xa4, 0xe8, 0x8a, 0x8f, 0xd0, 0x54, 0xfd, - 0x08, 0xca, 0x1a, 0x31, 0xfa, 0x1a, 0x79, 0xea, 0x13, 0xca, 0x70, 0x13, 0x2e, 0x3c, 0xf5, 0x89, - 0x67, 0x12, 0x5a, 0x47, 0x57, 0x73, 0x8d, 0xf2, 0xea, 0xa5, 0xa6, 0x80, 0x3f, 0xf6, 0x89, 0x77, - 0x28, 0x60, 0x5a, 0x04, 0x52, 0xef, 0x40, 0x25, 0x34, 0xa7, 0x43, 0xd7, 0xa1, 0x04, 0xaf, 0xc0, - 0x05, 0x8f, 0x50, 0xdf, 0x62, 0x91, 0xfd, 0xff, 0x32, 0xf6, 0x21, 0x4e, 0x8b, 0x50, 0xea, 0x8f, - 0x08, 0x2a, 0x49, 0x6a, 0xfc, 0x36, 0x60, 0xca, 0x0c, 0x8f, 0xe9, 0xcc, 0xb4, 0x09, 0x65, 0x86, - 0x3d, 0xd4, 0xed, 0x80, 0x0c, 0x35, 0x72, 0x5a, 0x8d, 0x6b, 0x3a, 0x91, 0xa2, 0x4d, 0x71, 0x03, - 0x6a, 0xc4, 0xe9, 0xa7, 0xb1, 0x33, 0x1c, 0x5b, 0x25, 0x4e, 0x3f, 0x89, 0xbc, 0x01, 0xb3, 0xb6, - 0xc1, 0x7a, 0xfb, 0xc4, 0xa3, 0xf5, 0x5c, 0xfa, 0x68, 0x5b, 0x46, 0x97, 0x58, 0xed, 0x50, 0xa9, - 0xc5, 0x28, 0xf5, 0x21, 0xcc, 0xa5, 0x9c, 0xc6, 0x1f, 0x00, 0xf0, 0x8d, 0x26, 0xc5, 0x67, 0xd8, - 0x6d, 0x06, 0xbb, 0xed, 0x72, 0xdd, 0x5a, 0xfe, 0xd9, 0x8b, 0x65, 0x49, 0x4b, 0xa0, 0xd5, 0x1f, - 0x10, 0x2c, 0x70, 0xb6, 0x5d, 0xe6, 0x11, 0xc3, 0x8e, 0x39, 0xef, 0x40, 0xb9, 0xb7, 0xef, 0x3b, - 0x07, 0x29, 0xd2, 0xa5, 0xc8, 0xb3, 0x31, 0xe5, 0xdd, 0x00, 0x24, 0x78, 0x93, 0x16, 0x19, 0xa7, - 0x66, 0xce, 0xe4, 0xd4, 0xaf, 0x08, 0x30, 0x3f, 0xfc, 0x27, 0x86, 0xe5, 0x13, 0x1a, 0xa5, 0xe0, - 0xff, 0x00, 0x56, 0x20, 0xd5, 0x1d, 0xc3, 0x26, 0x3c, 0xf4, 0x25, 0xad, 0xc4, 0x25, 0xdb, 0x86, - 0x4d, 0xa6, 0x64, 0x68, 0xe6, 0x0c, 0x19, 0xca, 0x4d, 0xcc, 0xd0, 0xcd, 0x44, 0x86, 0xf2, 0x57, - 0x51, 0xb2, 0x78, 0x92, 0x19, 0xa2, 0x89, 0x14, 0xdd, 0x82, 0x85, 0x94, 0xff, 0x22, 0xa8, 0xaf, - 0x41, 0x25, 0x3c, 0xc0, 0x57, 0x5c, 0xce, 0xa3, 0x5a, 0xd2, 0xca, 0xd6, 0x18, 0xaa, 0x1e, 0xc0, - 0xfc, 0x56, 0x74, 0x22, 0x7a, 0xce, 0xb5, 0xa7, 0xbe, 0x27, 0xc2, 0x2c, 0x36, 0x13, 0x5e, 0x2e, - 0x43, 0x79, 0x1c, 0xe6, 0xc8, 0x49, 0x88, 0xe3, 0x4c, 0x55, 0x0c, 0xb5, 0x27, 0x94, 0x78, 0xbb, - 0xcc, 0x60, 0x91, 0x8b, 0xea, 0x2f, 0x08, 0xe6, 0x13, 0x42, 0x41, 0x75, 0x2d, 0xea, 0x24, 0xa6, - 0xeb, 0xe8, 0x9e, 0xc1, 0xc2, 0xac, 0x21, 0x6d, 0x2e, 0x96, 0x6a, 0x06, 0x23, 0x41, 0x62, 0x1d, - 0xdf, 0xd6, 0xe3, 0x5a, 0x41, 0x8d, 0xbc, 0x56, 0x72, 0x7c, 0x3b, 0x2c, 0x90, 0xe0, 0xf8, 0xc6, - 0xd0, 0xd4, 0x33, 0x4c, 0x39, 0xce, 0x54, 0x33, 0x86, 0xe6, 0x66, 0x8a, 0xac, 0x09, 0x0b, 0x9e, - 0x6f, 0x91, 0x2c, 0x3c, 0xcf, 0xe1, 0xf3, 0x81, 0x2a, 0x85, 0x57, 0xbf, 0x80, 0x85, 0xc0, 0xf1, - 0xcd, 0x7b, 0x69, 0xd7, 0x97, 0xe0, 0x82, 0x4f, 0x89, 0xa7, 0x9b, 0x7d, 0x51, 0x69, 0xc5, 0x60, - 0xb9, 0xd9, 0xc7, 0xd7, 0x21, 0xdf, 0x37, 0x98, 0xc1, 0xdd, 0x2c, 0xaf, 0x5e, 0x8e, 0x4a, 0xe1, - 0xd4, 0xe1, 0x35, 0x0e, 0x53, 0xef, 0x03, 0x0e, 0x54, 0x34, 0xcd, 0x7e, 0x13, 0x0a, 0x34, 0x10, - 0x88, 0x8b, 0x75, 0x25, 0xc9, 0x92, 0xf1, 0x44, 0x0b, 0x91, 0xea, 0xcf, 0x08, 0x94, 0x36, 0x61, - 0x9e, 0xd9, 0xa3, 0x1b, 0xae, 0x97, 0xae, 0xbc, 0x73, 0xee, 0x51, 0xb7, 0xa0, 0x12, 0x95, 0xb6, - 0x4e, 0x09, 0x13, 0x7d, 0x6a, 0xca, 0x2d, 0x28, 0x47, 0xd0, 0x5d, 0xc2, 0xd4, 0x87, 0xb0, 0x3c, - 0xd5, 0x67, 0x11, 0x8a, 0x06, 0x14, 0x6d, 0x0e, 0x11, 0xb1, 0xa8, 0x8d, 0x9b, 0x44, 0x68, 0xaa, - 0x09, 0xbd, 0x5a, 0x87, 0x45, 0x41, 0xd6, 0x26, 0xcc, 0x08, 0xa2, 0x1b, 0x55, 0xdf, 0x0e, 0x2c, - 0x9d, 0xd2, 0x08, 0xfa, 0x77, 0x61, 0xd6, 0x16, 0x32, 0xb1, 0x41, 0x3d, 0xbb, 0x41, 0x6c, 0x13, - 0x23, 0xd5, 0x3f, 0x11, 0x5c, 0xcc, 0x34, 0xb9, 0x20, 0x5e, 0x7b, 0x9e, 0x6b, 0xeb, 0xd1, 0x6c, - 0x1c, 0x97, 0x46, 0x35, 0x90, 0x6f, 0x0a, 0xf1, 0x66, 0x3f, 0x59, 0x3b, 0x33, 0xa9, 0xda, 0x71, - 0xa0, 0xc8, 0xef, 0x51, 0xd4, 0xea, 0x17, 0xc6, 0xae, 0xf0, 0xe0, 0x3c, 0x32, 0x4c, 0x6f, 0xad, - 0x15, 0xf4, 0xc3, 0xdf, 0x5e, 0x2c, 0x9f, 0x69, 0x7a, 0x86, 0xf6, 0xad, 0xbe, 0x31, 0x64, 0xc4, - 0xd3, 0xc4, 0x2e, 0xf8, 0x2d, 0x28, 0x86, 0x3d, 0xb9, 0x9e, 0xe7, 0xfb, 0xcd, 0x45, 0x29, 0x4b, - 0xb6, 0x6d, 0x01, 0x51, 0xbf, 0x43, 0x50, 0x08, 0x4f, 0x7a, 0x5e, 0x75, 0x24, 0xc3, 0x2c, 0x71, - 0x7a, 0x6e, 0xdf, 0x74, 0x06, 0xfc, 0xfa, 0x16, 0xb4, 0x78, 0x8d, 0xb1, 0xb8, 0x56, 0xc1, 0x3d, - 0xad, 0x88, 0xbb, 0x53, 0x87, 0xc5, 0x8e, 0x67, 0x38, 0x74, 0x8f, 0x78, 0xdc, 0xb1, 0xb8, 0x68, - 0xd4, 0x16, 0xcc, 0xa5, 0xaa, 0x29, 0x35, 0x46, 0xd1, 0x2b, 0x8d, 0x51, 0x1d, 0x2a, 0x49, 0x0d, - 0xbe, 0x06, 0x79, 0x76, 0x38, 0x0c, 0x3b, 0x54, 0x75, 0x75, 0x3e, 0xb2, 0xe6, 0xea, 0xce, 0xe1, - 0x90, 0x68, 0x5c, 0x1d, 0xf8, 0xc9, 0xc7, 0x4f, 0x98, 0x58, 0xfe, 0x8d, 0x2f, 0x41, 0x81, 0x77, - 0x74, 0x7e, 0xa8, 0x92, 0x16, 0x2e, 0xd4, 0x6f, 0x11, 0x54, 0xc7, 0x35, 0xb4, 0x61, 0x5a, 0xe4, - 0xbf, 0x28, 0x21, 0x19, 0x66, 0xf7, 0x4c, 0x8b, 0x70, 0x1f, 0xc2, 0xed, 0xe2, 0xf5, 0xa4, 0x18, - 0xbe, 0xf9, 0x31, 0x94, 0xe2, 0x23, 0xe0, 0x12, 0x14, 0xd6, 0x1f, 0x3f, 0x69, 0x6d, 0xd5, 0x24, - 0x3c, 0x07, 0xa5, 0xed, 0x9d, 0x8e, 0x1e, 0x2e, 0x11, 0xbe, 0x08, 0x65, 0x6d, 0xfd, 0xfe, 0xfa, - 0x67, 0x7a, 0xbb, 0xd5, 0xb9, 0xfb, 0xa0, 0x36, 0x83, 0x31, 0x54, 0x43, 0xc1, 0xf6, 0x8e, 0x90, - 0xe5, 0x56, 0xff, 0x2a, 0xc0, 0x6c, 0xe4, 0x23, 0xbe, 0x0d, 0xf9, 0x47, 0x3e, 0xdd, 0xc7, 0x8b, - 0xe3, 0x1a, 0xfe, 0xd4, 0x33, 0x19, 0x11, 0x77, 0x52, 0x5e, 0x3a, 0x25, 0x17, 0xb9, 0x93, 0xf0, - 0xfb, 0x50, 0xe0, 0x6f, 0x0e, 0x3c, 0xf1, 0x15, 0x27, 0x4f, 0x7e, 0x9b, 0xa9, 0x12, 0xbe, 0x07, - 0xe5, 0xc4, 0x5b, 0x65, 0x8a, 0xf5, 0x95, 0x94, 0x34, 0xfd, 0xac, 0x51, 0xa5, 0x1b, 0x08, 0x3f, - 0x80, 0x72, 0x62, 0x38, 0x63, 0x39, 0x55, 0x27, 0xa9, 0x17, 0xc7, 0x98, 0x6b, 0xc2, 0x34, 0x57, - 0x25, 0xbc, 0x0e, 0x30, 0x9e, 0x9f, 0xf8, 0x72, 0x0a, 0x9c, 0x1c, 0xe0, 0xb2, 0x3c, 0x49, 0x15, - 0xd3, 0xac, 0x41, 0x29, 0x9e, 0x1e, 0xb8, 0x3e, 0x61, 0xa0, 0x84, 0x24, 0xd3, 0x47, 0x8d, 0x2a, - 0xe1, 0x0d, 0xa8, 0xb4, 0x2c, 0xeb, 0x55, 0x68, 0xe4, 0xa4, 0x86, 0x66, 0x79, 0xac, 0xb8, 0x93, - 0x66, 0x1b, 0x36, 0x7e, 0x3d, 0xbe, 0x12, 0xff, 0x38, 0x85, 0xe4, 0x37, 0xfe, 0x15, 0x17, 0xef, - 0xd6, 0x81, 0x8b, 0x99, 0xbe, 0x8d, 0x95, 0x8c, 0x75, 0xa6, 0xd5, 0xcb, 0xcb, 0x53, 0xf5, 0x31, - 0x6b, 0x1b, 0xaa, 0xe9, 0xb6, 0x81, 0xa7, 0x3d, 0x5c, 0xe5, 0x78, 0xb7, 0x29, 0x7d, 0x46, 0x6a, - 0xa0, 0xb5, 0x0f, 0x8f, 0x8e, 0x15, 0xe9, 0xf9, 0xb1, 0x22, 0xbd, 0x3c, 0x56, 0xd0, 0x37, 0x23, - 0x05, 0xfd, 0x34, 0x52, 0xd0, 0xb3, 0x91, 0x82, 0x8e, 0x46, 0x0a, 0xfa, 0x7d, 0xa4, 0xa0, 0x3f, - 0x46, 0x8a, 0xf4, 0x72, 0xa4, 0xa0, 0xef, 0x4f, 0x14, 0xe9, 0xe8, 0x44, 0x91, 0x9e, 0x9f, 0x28, - 0xd2, 0xe7, 0xc5, 0x9e, 0x65, 0x12, 0x87, 0x75, 0x8b, 0xfc, 0x7f, 0xe6, 0x9d, 0xbf, 0x03, 0x00, - 0x00, 0xff, 0xff, 0xf1, 0xa3, 0x32, 0xb1, 0x53, 0x0d, 0x00, 0x00, + // 1253 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x6f, 0x13, 0x57, + 0x10, 0xdf, 0x17, 0x7f, 0x10, 0x8f, 0x1d, 0xe3, 0xbc, 0x00, 0x31, 0x4b, 0xd9, 0xd0, 0x95, 0x68, + 0xad, 0xb6, 0x38, 0x90, 0x7e, 0x08, 0xaa, 0x56, 0xc8, 0x81, 0x00, 0x29, 0x98, 0xc0, 0xc6, 0xb4, + 0x55, 0xa5, 0x6a, 0xb5, 0xb6, 0x5f, 0x9c, 0x2d, 0xfb, 0xc5, 0xbe, 0xb7, 0x15, 0xdc, 0x2a, 0xf5, + 0x0f, 0x68, 0xd5, 0x53, 0xaf, 0xbd, 0xf5, 0xdc, 0x4b, 0x6f, 0x3d, 0xf5, 0xc0, 0x91, 0x23, 0xea, + 0x01, 0x15, 0x73, 0xe9, 0x91, 0xfe, 0x07, 0xd5, 0xbe, 0x7d, 0xbb, 0xde, 0xdd, 0xd8, 0x40, 0x24, + 0xd2, 0x9b, 0x77, 0xe6, 0x37, 0xf3, 0x7e, 0x6f, 0x66, 0xde, 0xcc, 0x18, 0xea, 0xa6, 0x33, 0x22, + 0x94, 0x11, 0xbf, 0xed, 0xf9, 0x2e, 0x73, 0x71, 0x79, 0xe0, 0xfa, 0x8c, 0xdc, 0x97, 0xcf, 0x8c, + 0x4c, 0xb6, 0x1b, 0xf4, 0xdb, 0x03, 0xd7, 0x5e, 0x1d, 0xb9, 0x23, 0x77, 0x95, 0xab, 0xfb, 0xc1, + 0x0e, 0xff, 0xe2, 0x1f, 0xfc, 0x57, 0x64, 0x26, 0x5f, 0x48, 0xc1, 0x23, 0x0f, 0x9e, 0xef, 0x7e, + 0x43, 0x06, 0x4c, 0x7c, 0xad, 0x7a, 0x77, 0x47, 0xb1, 0xa2, 0x2f, 0x7e, 0x44, 0xa6, 0xea, 0xa7, + 0x50, 0xd5, 0x88, 0x31, 0xd4, 0xc8, 0xbd, 0x80, 0x50, 0x86, 0xdb, 0x70, 0xe8, 0x5e, 0x40, 0x7c, + 0x93, 0xd0, 0x26, 0x3a, 0x55, 0x68, 0x55, 0xd7, 0x8e, 0xb4, 0x05, 0xfc, 0x76, 0x40, 0xfc, 0x07, + 0x02, 0xa6, 0xc5, 0x20, 0xf5, 0x22, 0xd4, 0x22, 0x73, 0xea, 0xb9, 0x0e, 0x25, 0x78, 0x15, 0x0e, + 0xf9, 0x84, 0x06, 0x16, 0x8b, 0xed, 0x8f, 0xe6, 0xec, 0x23, 0x9c, 0x16, 0xa3, 0xd4, 0x9f, 0x11, + 0xd4, 0xd2, 0xae, 0xf1, 0x7b, 0x80, 0x29, 0x33, 0x7c, 0xa6, 0x33, 0xd3, 0x26, 0x94, 0x19, 0xb6, + 0xa7, 0xdb, 0xa1, 0x33, 0xd4, 0x2a, 0x68, 0x0d, 0xae, 0xe9, 0xc5, 0x8a, 0x2e, 0xc5, 0x2d, 0x68, + 0x10, 0x67, 0x98, 0xc5, 0xce, 0x71, 0x6c, 0x9d, 0x38, 0xc3, 0x34, 0xf2, 0x2c, 0xcc, 0xdb, 0x06, + 0x1b, 0xec, 0x12, 0x9f, 0x36, 0x0b, 0xd9, 0xab, 0xdd, 0x30, 0xfa, 0xc4, 0xea, 0x46, 0x4a, 0x2d, + 0x41, 0xa9, 0xbf, 0x20, 0x38, 0xb2, 0x71, 0x9f, 0xd8, 0x9e, 0x65, 0xf8, 0xff, 0x0b, 0xc5, 0x73, + 0x7b, 0x28, 0x1e, 0x9d, 0x46, 0x91, 0xa6, 0x38, 0x5e, 0x87, 0x85, 0x4c, 0x60, 0xf1, 0xc7, 0x00, + 0xfc, 0xa4, 0x69, 0x39, 0xf4, 0xfa, 0xed, 0xf0, 0xb8, 0x6d, 0xae, 0x5b, 0x2f, 0x3e, 0x7c, 0xb2, + 0x22, 0x69, 0x29, 0xb4, 0xfa, 0x13, 0x82, 0x25, 0xee, 0x6d, 0x9b, 0xf9, 0xc4, 0xb0, 0x13, 0x9f, + 0x17, 0xa1, 0x3a, 0xd8, 0x0d, 0x9c, 0xbb, 0x19, 0xa7, 0xcb, 0x31, 0xb5, 0x89, 0xcb, 0x4b, 0x21, + 0x48, 0xf8, 0x4d, 0x5b, 0xe4, 0x48, 0xcd, 0xed, 0x8b, 0xd4, 0x36, 0x1c, 0xcd, 0x25, 0xe1, 0x35, + 0xdc, 0xf4, 0x0f, 0x04, 0x98, 0x87, 0xf4, 0x73, 0xc3, 0x0a, 0x08, 0x8d, 0x13, 0x7b, 0x12, 0xc0, + 0x0a, 0xa5, 0xba, 0x63, 0xd8, 0x84, 0x27, 0xb4, 0xa2, 0x55, 0xb8, 0xe4, 0xa6, 0x61, 0x93, 0x19, + 0x79, 0x9f, 0xdb, 0x47, 0xde, 0x0b, 0x2f, 0xcd, 0x7b, 0xf1, 0x14, 0x7a, 0x95, 0xbc, 0x9f, 0x87, + 0xa5, 0x0c, 0x7f, 0x11, 0x93, 0x37, 0xa1, 0x16, 0x5d, 0xe0, 0x5b, 0x2e, 0xe7, 0x51, 0xa9, 0x68, + 0x55, 0x6b, 0x02, 0x55, 0xef, 0xc2, 0xe2, 0x8d, 0xf8, 0x46, 0xf4, 0x80, 0x2b, 0x5a, 0xfd, 0x50, + 0x84, 0x59, 0x1c, 0x26, 0x58, 0xae, 0x40, 0x75, 0x12, 0xe6, 0x98, 0x24, 0x24, 0x71, 0xa6, 0x2a, + 0x86, 0xc6, 0x1d, 0x4a, 0xfc, 0x6d, 0x66, 0xb0, 0x98, 0xa2, 0xfa, 0x3b, 0x82, 0xc5, 0x94, 0x50, + 0xb8, 0x3a, 0x1d, 0xb7, 0x50, 0xd3, 0x75, 0x74, 0xdf, 0x60, 0x51, 0xd6, 0x90, 0xb6, 0x90, 0x48, + 0x35, 0x83, 0x91, 0x30, 0xb1, 0x4e, 0x60, 0xeb, 0x49, 0x01, 0xa2, 0x56, 0x51, 0xab, 0x38, 0x81, + 0x1d, 0x15, 0x48, 0x78, 0x7d, 0xc3, 0x33, 0xf5, 0x9c, 0xa7, 0x02, 0xf7, 0xd4, 0x30, 0x3c, 0x73, + 0x33, 0xe3, 0xac, 0x0d, 0x4b, 0x7e, 0x60, 0x91, 0x3c, 0xbc, 0xc8, 0xe1, 0x8b, 0xa1, 0x2a, 0x83, + 0x57, 0xbf, 0x86, 0xa5, 0x90, 0xf8, 0xe6, 0xe5, 0x2c, 0xf5, 0x65, 0x38, 0x14, 0x50, 0xe2, 0xeb, + 0xe6, 0x50, 0x54, 0x5a, 0x39, 0xfc, 0xdc, 0x1c, 0xe2, 0x33, 0x50, 0x1c, 0x1a, 0xcc, 0xe0, 0x34, + 0xab, 0x6b, 0xc7, 0xe3, 0x52, 0xd8, 0x73, 0x79, 0x8d, 0xc3, 0xd4, 0xab, 0x80, 0x43, 0x15, 0xcd, + 0x7a, 0x3f, 0x07, 0x25, 0x1a, 0x0a, 0xc4, 0xc3, 0x38, 0x91, 0xf6, 0x92, 0x63, 0xa2, 0x45, 0x48, + 0xf5, 0x37, 0x04, 0x4a, 0x97, 0x30, 0xdf, 0x1c, 0xd0, 0x2b, 0xae, 0x9f, 0xad, 0xbc, 0x03, 0xee, + 0x7c, 0xe7, 0xa1, 0x16, 0x97, 0xb6, 0x4e, 0x09, 0x7b, 0x71, 0xf7, 0xab, 0xc6, 0xd0, 0x6d, 0xc2, + 0xd4, 0xeb, 0xb0, 0x32, 0x93, 0xb3, 0x08, 0x45, 0x0b, 0xca, 0x36, 0x87, 0x88, 0x58, 0x34, 0x26, + 0x4d, 0x22, 0x32, 0xd5, 0x84, 0x5e, 0x6d, 0xc2, 0x31, 0xe1, 0xac, 0x4b, 0x98, 0x11, 0x46, 0x37, + 0xae, 0xbe, 0x2d, 0x58, 0xde, 0xa3, 0x11, 0xee, 0x3f, 0x80, 0x79, 0x5b, 0xc8, 0xc4, 0x01, 0xcd, + 0xfc, 0x01, 0x89, 0x4d, 0x82, 0x54, 0xff, 0x45, 0x70, 0x38, 0xd7, 0x39, 0xc3, 0x78, 0xed, 0xf8, + 0xae, 0xad, 0xc7, 0x4b, 0xc1, 0xa4, 0x34, 0xea, 0xa1, 0x7c, 0x53, 0x88, 0x37, 0x87, 0xe9, 0xda, + 0x99, 0xcb, 0xd4, 0x8e, 0x03, 0x65, 0xfe, 0x8e, 0xe2, 0x01, 0xb2, 0x34, 0xa1, 0xc2, 0x83, 0x73, + 0xcb, 0x30, 0xfd, 0xf5, 0x4e, 0xd8, 0x0f, 0xff, 0x7a, 0xb2, 0xb2, 0xaf, 0xb5, 0x21, 0xb2, 0xef, + 0x0c, 0x0d, 0x8f, 0x11, 0x5f, 0x13, 0xa7, 0xe0, 0x77, 0xa1, 0x1c, 0x35, 0xfa, 0x66, 0x91, 0x9f, + 0xb7, 0x10, 0xa7, 0x2c, 0x3d, 0x0b, 0x04, 0x44, 0xfd, 0x01, 0x41, 0x29, 0xba, 0xe9, 0x41, 0xd5, + 0x91, 0x0c, 0xf3, 0xc4, 0x19, 0xb8, 0x43, 0xd3, 0x19, 0xf1, 0xe7, 0x5b, 0xd2, 0x92, 0x6f, 0x8c, + 0xc5, 0xb3, 0x0a, 0xdf, 0x69, 0x4d, 0xbc, 0x9d, 0x26, 0x1c, 0xeb, 0xf9, 0x86, 0x43, 0x77, 0x88, + 0xcf, 0x89, 0x25, 0x45, 0xa3, 0x76, 0x60, 0x21, 0x53, 0x4d, 0x99, 0xfd, 0x01, 0xbd, 0xd2, 0xfe, + 0xa0, 0x43, 0x2d, 0xad, 0xc1, 0xa7, 0xa1, 0xc8, 0x1e, 0x78, 0x51, 0x87, 0xaa, 0xaf, 0x2d, 0xc6, + 0xd6, 0x5c, 0xdd, 0x7b, 0xe0, 0x11, 0x8d, 0xab, 0x43, 0x9e, 0x7c, 0xfc, 0x44, 0x89, 0xe5, 0xbf, + 0xf1, 0x11, 0x28, 0xf1, 0x8e, 0xce, 0x2f, 0x55, 0xd1, 0xa2, 0x0f, 0xf5, 0x7b, 0x04, 0xf5, 0x49, + 0x0d, 0x5d, 0x31, 0x2d, 0xf2, 0x3a, 0x4a, 0x48, 0x86, 0xf9, 0x1d, 0xd3, 0x22, 0x9c, 0x43, 0x74, + 0x5c, 0xf2, 0x3d, 0x2d, 0x86, 0xef, 0x7c, 0x06, 0x95, 0xe4, 0x0a, 0xb8, 0x02, 0xa5, 0x8d, 0xdb, + 0x77, 0x3a, 0x37, 0x1a, 0x12, 0x5e, 0x80, 0xca, 0xcd, 0xad, 0x9e, 0x1e, 0x7d, 0x22, 0x7c, 0x18, + 0xaa, 0xda, 0xc6, 0xd5, 0x8d, 0x2f, 0xf5, 0x6e, 0xa7, 0x77, 0xe9, 0x5a, 0x63, 0x0e, 0x63, 0xa8, + 0x47, 0x82, 0x9b, 0x5b, 0x42, 0x56, 0x58, 0xfb, 0xb3, 0x0c, 0xf3, 0x31, 0x47, 0x7c, 0x01, 0x8a, + 0xb7, 0x02, 0xba, 0x8b, 0x8f, 0x4d, 0x6a, 0xf8, 0x0b, 0xdf, 0x64, 0x44, 0xbc, 0x49, 0x79, 0x79, + 0x8f, 0x5c, 0xe4, 0x4e, 0xc2, 0x1f, 0x41, 0x89, 0x2f, 0x0b, 0x78, 0xea, 0xfa, 0x2a, 0x4f, 0x5f, + 0x4a, 0x55, 0x09, 0x5f, 0x86, 0x6a, 0x6a, 0x01, 0x9a, 0x61, 0x7d, 0x22, 0x23, 0xcd, 0xee, 0x4a, + 0xaa, 0x74, 0x16, 0xe1, 0x2d, 0xa8, 0x73, 0x55, 0xbc, 0xb7, 0x50, 0xfc, 0x46, 0x6c, 0x32, 0x6d, + 0x9f, 0x94, 0x4f, 0xce, 0xd0, 0x26, 0xb4, 0xae, 0x41, 0x35, 0x35, 0xed, 0xb1, 0x9c, 0x29, 0xbc, + 0xcc, 0x0a, 0x33, 0x21, 0x37, 0x65, 0x3d, 0x50, 0x25, 0xbc, 0x01, 0x30, 0x19, 0xc8, 0xf8, 0x78, + 0x06, 0x9c, 0xde, 0x08, 0x64, 0x79, 0x9a, 0x2a, 0x71, 0xb3, 0x0e, 0x95, 0x64, 0x1c, 0xe1, 0xe6, + 0x94, 0x09, 0x15, 0x39, 0x99, 0x3d, 0xbb, 0x54, 0x09, 0x5f, 0x81, 0x5a, 0xc7, 0xb2, 0x5e, 0xc5, + 0x8d, 0x9c, 0xd6, 0xd0, 0xbc, 0x1f, 0x2b, 0x69, 0xcd, 0xf9, 0x09, 0x80, 0xdf, 0x4a, 0xde, 0xd8, + 0x0b, 0xc7, 0x9a, 0xfc, 0xf6, 0x4b, 0x71, 0xc9, 0x69, 0x3d, 0x38, 0x9c, 0x1b, 0x04, 0x58, 0xc9, + 0x59, 0xe7, 0x66, 0x87, 0xbc, 0x32, 0x53, 0x9f, 0x78, 0xed, 0x42, 0x3d, 0xdb, 0x87, 0xf0, 0xac, + 0xf5, 0x5a, 0x4e, 0x4e, 0x9b, 0xd1, 0xb8, 0xa4, 0x16, 0x5a, 0xff, 0xe4, 0xd1, 0x53, 0x45, 0x7a, + 0xfc, 0x54, 0x91, 0x9e, 0x3f, 0x55, 0xd0, 0x77, 0x63, 0x05, 0xfd, 0x3a, 0x56, 0xd0, 0xc3, 0xb1, + 0x82, 0x1e, 0x8d, 0x15, 0xf4, 0xf7, 0x58, 0x41, 0xff, 0x8c, 0x15, 0xe9, 0xf9, 0x58, 0x41, 0x3f, + 0x3e, 0x53, 0xa4, 0x47, 0xcf, 0x14, 0xe9, 0xf1, 0x33, 0x45, 0xfa, 0xaa, 0x3c, 0xb0, 0x4c, 0xe2, + 0xb0, 0x7e, 0x99, 0xff, 0x33, 0x7c, 0xff, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0e, 0x4f, 0x5c, + 0xe0, 0x9d, 0x0e, 0x00, 0x00, } func (x MatchType) String() string { @@ -1423,6 +1530,41 @@ func (this *QueryRequest) Equal(that interface{}) bool { } return true } +func (this *ExemplarQueryRequest) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ExemplarQueryRequest) + if !ok { + that2, ok := that.(ExemplarQueryRequest) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.StartTimestampMs != that1.StartTimestampMs { + return false + } + if this.EndTimestampMs != that1.EndTimestampMs { + return false + } + if len(this.Matchers) != len(that1.Matchers) { + return false + } + for i := range this.Matchers { + if !this.Matchers[i].Equal(that1.Matchers[i]) { + return false + } + } + return true +} func (this *QueryResponse) Equal(that interface{}) bool { if that == nil { return this == nil @@ -1489,6 +1631,35 @@ func (this *QueryStreamResponse) Equal(that interface{}) bool { } return true } +func (this *ExemplarQueryResponse) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ExemplarQueryResponse) + if !ok { + that2, ok := that.(ExemplarQueryResponse) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if len(this.Timeseries) != len(that1.Timeseries) { + return false + } + for i := range this.Timeseries { + if !this.Timeseries[i].Equal(&that1.Timeseries[i]) { + return false + } + } + return true +} func (this *LabelValuesRequest) Equal(that interface{}) bool { if that == nil { return this == nil @@ -2058,6 +2229,20 @@ func (this *QueryRequest) GoString() string { s = append(s, "}") return strings.Join(s, "") } +func (this *ExemplarQueryRequest) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 7) + s = append(s, "&client.ExemplarQueryRequest{") + s = append(s, "StartTimestampMs: "+fmt.Sprintf("%#v", this.StartTimestampMs)+",\n") + s = append(s, "EndTimestampMs: "+fmt.Sprintf("%#v", this.EndTimestampMs)+",\n") + if this.Matchers != nil { + s = append(s, "Matchers: "+fmt.Sprintf("%#v", this.Matchers)+",\n") + } + s = append(s, "}") + return strings.Join(s, "") +} func (this *QueryResponse) GoString() string { if this == nil { return "nil" @@ -2097,6 +2282,22 @@ func (this *QueryStreamResponse) GoString() string { s = append(s, "}") return strings.Join(s, "") } +func (this *ExemplarQueryResponse) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 5) + s = append(s, "&client.ExemplarQueryResponse{") + if this.Timeseries != nil { + vs := make([]*cortexpb.TimeSeries, len(this.Timeseries)) + for i := range vs { + vs[i] = &this.Timeseries[i] + } + s = append(s, "Timeseries: "+fmt.Sprintf("%#v", vs)+",\n") + } + s = append(s, "}") + return strings.Join(s, "") +} func (this *LabelValuesRequest) GoString() string { if this == nil { return "nil" @@ -2339,6 +2540,7 @@ type IngesterClient interface { Push(ctx context.Context, in *cortexpb.WriteRequest, opts ...grpc.CallOption) (*cortexpb.WriteResponse, error) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) QueryStream(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (Ingester_QueryStreamClient, error) + QueryExemplars(ctx context.Context, in *ExemplarQueryRequest, opts ...grpc.CallOption) (*ExemplarQueryResponse, error) LabelValues(ctx context.Context, in *LabelValuesRequest, opts ...grpc.CallOption) (*LabelValuesResponse, error) LabelNames(ctx context.Context, in *LabelNamesRequest, opts ...grpc.CallOption) (*LabelNamesResponse, error) UserStats(ctx context.Context, in *UserStatsRequest, opts ...grpc.CallOption) (*UserStatsResponse, error) @@ -2407,6 +2609,15 @@ func (x *ingesterQueryStreamClient) Recv() (*QueryStreamResponse, error) { return m, nil } +func (c *ingesterClient) QueryExemplars(ctx context.Context, in *ExemplarQueryRequest, opts ...grpc.CallOption) (*ExemplarQueryResponse, error) { + out := new(ExemplarQueryResponse) + err := c.cc.Invoke(ctx, "/cortex.Ingester/QueryExemplars", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *ingesterClient) LabelValues(ctx context.Context, in *LabelValuesRequest, opts ...grpc.CallOption) (*LabelValuesResponse, error) { out := new(LabelValuesResponse) err := c.cc.Invoke(ctx, "/cortex.Ingester/LabelValues", in, out, opts...) @@ -2500,6 +2711,7 @@ type IngesterServer interface { Push(context.Context, *cortexpb.WriteRequest) (*cortexpb.WriteResponse, error) Query(context.Context, *QueryRequest) (*QueryResponse, error) QueryStream(*QueryRequest, Ingester_QueryStreamServer) error + QueryExemplars(context.Context, *ExemplarQueryRequest) (*ExemplarQueryResponse, error) LabelValues(context.Context, *LabelValuesRequest) (*LabelValuesResponse, error) LabelNames(context.Context, *LabelNamesRequest) (*LabelNamesResponse, error) UserStats(context.Context, *UserStatsRequest) (*UserStatsResponse, error) @@ -2523,6 +2735,9 @@ func (*UnimplementedIngesterServer) Query(ctx context.Context, req *QueryRequest func (*UnimplementedIngesterServer) QueryStream(req *QueryRequest, srv Ingester_QueryStreamServer) error { return status.Errorf(codes.Unimplemented, "method QueryStream not implemented") } +func (*UnimplementedIngesterServer) QueryExemplars(ctx context.Context, req *ExemplarQueryRequest) (*ExemplarQueryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryExemplars not implemented") +} func (*UnimplementedIngesterServer) LabelValues(ctx context.Context, req *LabelValuesRequest) (*LabelValuesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method LabelValues not implemented") } @@ -2606,6 +2821,24 @@ func (x *ingesterQueryStreamServer) Send(m *QueryStreamResponse) error { return x.ServerStream.SendMsg(m) } +func _Ingester_QueryExemplars_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExemplarQueryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IngesterServer).QueryExemplars(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cortex.Ingester/QueryExemplars", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IngesterServer).QueryExemplars(ctx, req.(*ExemplarQueryRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Ingester_LabelValues_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(LabelValuesRequest) if err := dec(in); err != nil { @@ -2752,6 +2985,10 @@ var _Ingester_serviceDesc = grpc.ServiceDesc{ MethodName: "Query", Handler: _Ingester_Query_Handler, }, + { + MethodName: "QueryExemplars", + Handler: _Ingester_QueryExemplars_Handler, + }, { MethodName: "LabelValues", Handler: _Ingester_LabelValues_Handler, @@ -2913,7 +3150,7 @@ func (m *QueryRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryResponse) Marshal() (dAtA []byte, err error) { +func (m *ExemplarQueryRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2923,20 +3160,20 @@ func (m *QueryResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *ExemplarQueryRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *ExemplarQueryRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Timeseries) > 0 { - for iNdEx := len(m.Timeseries) - 1; iNdEx >= 0; iNdEx-- { + if len(m.Matchers) > 0 { + for iNdEx := len(m.Matchers) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Timeseries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Matchers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -2944,13 +3181,23 @@ func (m *QueryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintIngester(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0xa + dAtA[i] = 0x1a } } + if m.EndTimestampMs != 0 { + i = encodeVarintIngester(dAtA, i, uint64(m.EndTimestampMs)) + i-- + dAtA[i] = 0x10 + } + if m.StartTimestampMs != 0 { + i = encodeVarintIngester(dAtA, i, uint64(m.StartTimestampMs)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } -func (m *QueryStreamResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2960,12 +3207,100 @@ func (m *QueryStreamResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryStreamResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryStreamResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Timeseries) > 0 { + for iNdEx := len(m.Timeseries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Timeseries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIngester(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryStreamResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryStreamResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryStreamResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Timeseries) > 0 { + for iNdEx := len(m.Timeseries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Timeseries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIngester(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Chunkseries) > 0 { + for iNdEx := len(m.Chunkseries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Chunkseries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIngester(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ExemplarQueryResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExemplarQueryResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExemplarQueryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -2981,20 +3316,6 @@ func (m *QueryStreamResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintIngester(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 - } - } - if len(m.Chunkseries) > 0 { - for iNdEx := len(m.Chunkseries) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Chunkseries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintIngester(dAtA, i, uint64(size)) - } - i-- dAtA[i] = 0xa } } @@ -3767,6 +4088,27 @@ func (m *QueryRequest) Size() (n int) { return n } +func (m *ExemplarQueryRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.StartTimestampMs != 0 { + n += 1 + sovIngester(uint64(m.StartTimestampMs)) + } + if m.EndTimestampMs != 0 { + n += 1 + sovIngester(uint64(m.EndTimestampMs)) + } + if len(m.Matchers) > 0 { + for _, e := range m.Matchers { + l = e.Size() + n += 1 + l + sovIngester(uint64(l)) + } + } + return n +} + func (m *QueryResponse) Size() (n int) { if m == nil { return 0 @@ -3803,6 +4145,21 @@ func (m *QueryStreamResponse) Size() (n int) { return n } +func (m *ExemplarQueryResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Timeseries) > 0 { + for _, e := range m.Timeseries { + l = e.Size() + n += 1 + l + sovIngester(uint64(l)) + } + } + return n +} + func (m *LabelValuesRequest) Size() (n int) { if m == nil { return 0 @@ -4166,6 +4523,23 @@ func (this *QueryRequest) String() string { }, "") return s } +func (this *ExemplarQueryRequest) String() string { + if this == nil { + return "nil" + } + repeatedStringForMatchers := "[]*LabelMatchers{" + for _, f := range this.Matchers { + repeatedStringForMatchers += strings.Replace(f.String(), "LabelMatchers", "LabelMatchers", 1) + "," + } + repeatedStringForMatchers += "}" + s := strings.Join([]string{`&ExemplarQueryRequest{`, + `StartTimestampMs:` + fmt.Sprintf("%v", this.StartTimestampMs) + `,`, + `EndTimestampMs:` + fmt.Sprintf("%v", this.EndTimestampMs) + `,`, + `Matchers:` + repeatedStringForMatchers + `,`, + `}`, + }, "") + return s +} func (this *QueryResponse) String() string { if this == nil { return "nil" @@ -4202,6 +4576,21 @@ func (this *QueryStreamResponse) String() string { }, "") return s } +func (this *ExemplarQueryResponse) String() string { + if this == nil { + return "nil" + } + repeatedStringForTimeseries := "[]TimeSeries{" + for _, f := range this.Timeseries { + repeatedStringForTimeseries += fmt.Sprintf("%v", f) + "," + } + repeatedStringForTimeseries += "}" + s := strings.Join([]string{`&ExemplarQueryResponse{`, + `Timeseries:` + repeatedStringForTimeseries + `,`, + `}`, + }, "") + return s +} func (this *LabelValuesRequest) String() string { if this == nil { return "nil" @@ -4737,6 +5126,131 @@ func (m *QueryRequest) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExemplarQueryRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExemplarQueryRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExemplarQueryRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTimestampMs", wireType) + } + m.StartTimestampMs = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTimestampMs |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTimestampMs", wireType) + } + m.EndTimestampMs = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTimestampMs |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Matchers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthIngester + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIngester + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Matchers = append(m.Matchers, &LabelMatchers{}) + if err := m.Matchers[len(m.Matchers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipIngester(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -4945,6 +5459,93 @@ func (m *QueryStreamResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExemplarQueryResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExemplarQueryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExemplarQueryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Timeseries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthIngester + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIngester + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Timeseries = append(m.Timeseries, cortexpb.TimeSeries{}) + if err := m.Timeseries[len(m.Timeseries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipIngester(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *LabelValuesRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/vendor/github.com/cortexproject/cortex/pkg/ingester/client/ingester.proto b/vendor/github.com/cortexproject/cortex/pkg/ingester/client/ingester.proto index 35a274e6e6c3..0314139fcece 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ingester/client/ingester.proto +++ b/vendor/github.com/cortexproject/cortex/pkg/ingester/client/ingester.proto @@ -15,6 +15,7 @@ service Ingester { rpc Push(cortexpb.WriteRequest) returns (cortexpb.WriteResponse) {}; rpc Query(QueryRequest) returns (QueryResponse) {}; rpc QueryStream(QueryRequest) returns (stream QueryStreamResponse) {}; + rpc QueryExemplars(ExemplarQueryRequest) returns (ExemplarQueryResponse) {}; rpc LabelValues(LabelValuesRequest) returns (LabelValuesResponse) {}; rpc LabelNames(LabelNamesRequest) returns (LabelNamesResponse) {}; @@ -41,6 +42,12 @@ message QueryRequest { repeated LabelMatcher matchers = 3; } +message ExemplarQueryRequest { + int64 start_timestamp_ms = 1; + int64 end_timestamp_ms = 2; + repeated LabelMatchers matchers = 3; +} + message QueryResponse { repeated cortexpb.TimeSeries timeseries = 1 [(gogoproto.nullable) = false]; } @@ -51,6 +58,10 @@ message QueryStreamResponse { repeated cortexpb.TimeSeries timeseries = 2 [(gogoproto.nullable) = false]; } +message ExemplarQueryResponse { + repeated cortexpb.TimeSeries timeseries = 1 [(gogoproto.nullable) = false]; +} + message LabelValuesRequest { string label_name = 1; int64 start_timestamp_ms = 2; diff --git a/vendor/github.com/cortexproject/cortex/pkg/ingester/ingester.go b/vendor/github.com/cortexproject/cortex/pkg/ingester/ingester.go index 7f387b04abb1..7936a6d3f657 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ingester/ingester.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ingester/ingester.go @@ -6,6 +6,7 @@ import ( "fmt" "net/http" "os" + "strings" "sync" "time" @@ -98,6 +99,8 @@ type Config struct { DefaultLimits InstanceLimits `yaml:"instance_limits"` InstanceLimitsFn func() *InstanceLimits `yaml:"-"` + IgnoreSeriesLimitForMetricNames string `yaml:"ignore_series_limit_for_metric_names"` + // For testing, you can override the address and ID of this ingester. ingesterClientFactory func(addr string, cfg client.Config) (client.HealthAndIngesterClient, error) } @@ -122,7 +125,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { f.DurationVar(&cfg.MetadataRetainPeriod, "ingester.metadata-retain-period", 10*time.Minute, "Period at which metadata we have not seen will remain in memory before being deleted.") f.DurationVar(&cfg.RateUpdatePeriod, "ingester.rate-update-period", 15*time.Second, "Period with which to update the per-user ingestion rates.") - f.BoolVar(&cfg.ActiveSeriesMetricsEnabled, "ingester.active-series-metrics-enabled", false, "Enable tracking of active series and export them as metrics.") + f.BoolVar(&cfg.ActiveSeriesMetricsEnabled, "ingester.active-series-metrics-enabled", true, "Enable tracking of active series and export them as metrics.") f.DurationVar(&cfg.ActiveSeriesMetricsUpdatePeriod, "ingester.active-series-metrics-update-period", 1*time.Minute, "How often to update active series metrics.") f.DurationVar(&cfg.ActiveSeriesMetricsIdleTimeout, "ingester.active-series-metrics-idle-timeout", 10*time.Minute, "After what time a series is considered to be inactive.") f.BoolVar(&cfg.StreamChunksWhenUsingBlocks, "ingester.stream-chunks-when-using-blocks", false, "Stream chunks when using blocks. This is experimental feature and not yet tested. Once ready, it will be made default and this config option removed.") @@ -131,6 +134,29 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { f.Int64Var(&cfg.DefaultLimits.MaxInMemoryTenants, "ingester.instance-limits.max-tenants", 0, "Max users that this ingester can hold. Requests from additional users will be rejected. This limit only works when using blocks engine. 0 = unlimited.") f.Int64Var(&cfg.DefaultLimits.MaxInMemorySeries, "ingester.instance-limits.max-series", 0, "Max series that this ingester can hold (across all tenants). Requests to create additional series will be rejected. This limit only works when using blocks engine. 0 = unlimited.") f.Int64Var(&cfg.DefaultLimits.MaxInflightPushRequests, "ingester.instance-limits.max-inflight-push-requests", 0, "Max inflight push requests that this ingester can handle (across all tenants). Additional requests will be rejected. 0 = unlimited.") + + f.StringVar(&cfg.IgnoreSeriesLimitForMetricNames, "ingester.ignore-series-limit-for-metric-names", "", "Comma-separated list of metric names, for which -ingester.max-series-per-metric and -ingester.max-global-series-per-metric limits will be ignored. Does not affect max-series-per-user or max-global-series-per-metric limits.") +} + +func (cfg *Config) getIgnoreSeriesLimitForMetricNamesMap() map[string]struct{} { + if cfg.IgnoreSeriesLimitForMetricNames == "" { + return nil + } + + result := map[string]struct{}{} + + for _, s := range strings.Split(cfg.IgnoreSeriesLimitForMetricNames, ",") { + tr := strings.TrimSpace(s) + if tr != "" { + result[tr] = struct{}{} + } + } + + if len(result) == 0 { + return nil + } + + return result } // Ingester deals with "in flight" chunks. Based on Prometheus 1.x @@ -885,6 +911,19 @@ func (i *Ingester) QueryStream(req *client.QueryRequest, stream client.Ingester_ return err } +// Query implements service.IngesterServer +func (i *Ingester) QueryExemplars(ctx context.Context, req *client.ExemplarQueryRequest) (*client.ExemplarQueryResponse, error) { + if err := i.checkRunningOrStopping(); err != nil { + return nil, err + } + + if !i.cfg.BlocksStorageEnabled { + return nil, errors.New("not supported") + } + + return i.v2QueryExemplars(ctx, req) +} + // LabelValues returns all label values that are associated with a given label name. func (i *Ingester) LabelValues(ctx context.Context, req *client.LabelValuesRequest) (*client.LabelValuesResponse, error) { if err := i.checkRunningOrStopping(); err != nil { diff --git a/vendor/github.com/cortexproject/cortex/pkg/ingester/ingester_v2.go b/vendor/github.com/cortexproject/cortex/pkg/ingester/ingester_v2.go index 3ffdcfc2d4c3..d43e09ac9c82 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ingester/ingester_v2.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ingester/ingester_v2.go @@ -157,6 +157,10 @@ func (u *userTSDB) ChunkQuerier(ctx context.Context, mint, maxt int64) (storage. return u.db.ChunkQuerier(ctx, mint, maxt) } +func (u *userTSDB) ExemplarQuerier(ctx context.Context) (storage.ExemplarQuerier, error) { + return u.db.ExemplarQuerier(ctx) +} + func (u *userTSDB) Head() *tsdb.Head { return u.db.Head() } @@ -1031,6 +1035,53 @@ func (i *Ingester) v2Query(ctx context.Context, req *client.QueryRequest) (*clie return result, ss.Err() } +func (i *Ingester) v2QueryExemplars(ctx context.Context, req *client.ExemplarQueryRequest) (*client.ExemplarQueryResponse, error) { + userID, err := tenant.TenantID(ctx) + if err != nil { + return nil, err + } + + from, through, matchers, err := client.FromExemplarQueryRequest(req) + if err != nil { + return nil, err + } + + i.metrics.queries.Inc() + + db := i.getTSDB(userID) + if db == nil { + return &client.ExemplarQueryResponse{}, nil + } + + q, err := db.ExemplarQuerier(ctx) + if err != nil { + return nil, err + } + + // It's not required to sort series from a single ingester because series are sorted by the Exemplar Storage before returning from Select. + res, err := q.Select(from, through, matchers...) + if err != nil { + return nil, err + } + + numExemplars := 0 + + result := &client.ExemplarQueryResponse{} + for _, es := range res { + ts := cortexpb.TimeSeries{ + Labels: cortexpb.FromLabelsToLabelAdapters(es.SeriesLabels), + Exemplars: cortexpb.FromExemplarsToExemplarProtos(es.Exemplars), + } + + numExemplars += len(ts.Exemplars) + result.Timeseries = append(result.Timeseries, ts) + } + + i.metrics.queriedExemplars.Observe(float64(numExemplars)) + + return result, nil +} + func (i *Ingester) v2LabelValues(ctx context.Context, req *client.LabelValuesRequest) (*client.LabelValuesResponse, error) { labelName, startTimestampMs, endTimestampMs, matchers, err := client.FromLabelValuesRequest(req) if err != nil { @@ -1507,7 +1558,7 @@ func (i *Ingester) createTSDB(userID string) (*userTSDB, error) { userDB := &userTSDB{ userID: userID, activeSeries: NewActiveSeries(), - seriesInMetric: newMetricCounter(i.limiter), + seriesInMetric: newMetricCounter(i.limiter, i.cfg.getIgnoreSeriesLimitForMetricNamesMap()), ingestedAPISamples: util_math.NewEWMARate(0.2, i.cfg.RateUpdatePeriod), ingestedRuleSamples: util_math.NewEWMARate(0.2, i.cfg.RateUpdatePeriod), diff --git a/vendor/github.com/cortexproject/cortex/pkg/ingester/metrics.go b/vendor/github.com/cortexproject/cortex/pkg/ingester/metrics.go index 8ab1a376ac7b..585cc45df940 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ingester/metrics.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ingester/metrics.go @@ -27,6 +27,7 @@ type ingesterMetrics struct { ingestedMetadataFail prometheus.Counter queries prometheus.Counter queriedSamples prometheus.Histogram + queriedExemplars prometheus.Histogram queriedSeries prometheus.Histogram queriedChunks prometheus.Histogram memSeries prometheus.Gauge @@ -113,6 +114,12 @@ func newIngesterMetrics(r prometheus.Registerer, createMetricsConflictingWithTSD // Could easily return 10m samples per query - 10*(8^(8-1)) = 20.9m. Buckets: prometheus.ExponentialBuckets(10, 8, 8), }), + queriedExemplars: promauto.With(r).NewHistogram(prometheus.HistogramOpts{ + Name: "cortex_ingester_queried_exemplars", + Help: "The total number of exemplars returned from queries.", + // A reasonable upper bound is around 6k - 10*(5^(5-1)) = 6250. + Buckets: prometheus.ExponentialBuckets(10, 5, 5), + }), queriedSeries: promauto.With(r).NewHistogram(prometheus.HistogramOpts{ Name: "cortex_ingester_queried_series", Help: "The total number of series returned from queries.", diff --git a/vendor/github.com/cortexproject/cortex/pkg/ingester/user_state.go b/vendor/github.com/cortexproject/cortex/pkg/ingester/user_state.go index aeccec2f23de..9f4d00077596 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ingester/user_state.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ingester/user_state.go @@ -145,7 +145,7 @@ func (us *userStates) getOrCreate(userID string) *userState { index: index.New(), ingestedAPISamples: util_math.NewEWMARate(0.2, us.cfg.RateUpdatePeriod), ingestedRuleSamples: util_math.NewEWMARate(0.2, us.cfg.RateUpdatePeriod), - seriesInMetric: newMetricCounter(us.limiter), + seriesInMetric: newMetricCounter(us.limiter, us.cfg.getIgnoreSeriesLimitForMetricNamesMap()), logger: logger, memSeries: us.metrics.memSeries, @@ -362,9 +362,11 @@ type metricCounterShard struct { type metricCounter struct { limiter *Limiter shards []metricCounterShard + + ignoredMetrics map[string]struct{} } -func newMetricCounter(limiter *Limiter) *metricCounter { +func newMetricCounter(limiter *Limiter, ignoredMetricsForSeriesCount map[string]struct{}) *metricCounter { shards := make([]metricCounterShard, 0, numMetricCounterShards) for i := 0; i < numMetricCounterShards; i++ { shards = append(shards, metricCounterShard{ @@ -374,6 +376,8 @@ func newMetricCounter(limiter *Limiter) *metricCounter { return &metricCounter{ limiter: limiter, shards: shards, + + ignoredMetrics: ignoredMetricsForSeriesCount, } } @@ -394,6 +398,10 @@ func (m *metricCounter) getShard(metricName string) *metricCounterShard { } func (m *metricCounter) canAddSeriesFor(userID, metric string) error { + if _, ok := m.ignoredMetrics[metric]; ok { + return nil + } + shard := m.getShard(metric) shard.mtx.Lock() defer shard.mtx.Unlock() diff --git a/vendor/github.com/cortexproject/cortex/pkg/querier/batch/batch.go b/vendor/github.com/cortexproject/cortex/pkg/querier/batch/batch.go index 2517899dff85..051dd9bc98e3 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/querier/batch/batch.go +++ b/vendor/github.com/cortexproject/cortex/pkg/querier/batch/batch.go @@ -49,7 +49,7 @@ type iterator interface { Err() error } -// NewChunkMergeIterator returns a storage.SeriesIterator that merges Cortex chunks together. +// NewChunkMergeIterator returns a chunkenc.Iterator that merges Cortex chunks together. func NewChunkMergeIterator(chunks []chunk.Chunk, _, _ model.Time) chunkenc.Iterator { converted := make([]GenericChunk, len(chunks)) for i, c := range chunks { @@ -59,13 +59,13 @@ func NewChunkMergeIterator(chunks []chunk.Chunk, _, _ model.Time) chunkenc.Itera return NewGenericChunkMergeIterator(converted) } -// NewGenericChunkMergeIterator returns a storage.SeriesIterator that merges generic chunks together. +// NewGenericChunkMergeIterator returns a chunkenc.Iterator that merges generic chunks together. func NewGenericChunkMergeIterator(chunks []GenericChunk) chunkenc.Iterator { iter := newMergeIterator(chunks) return newIteratorAdapter(iter) } -// iteratorAdapter turns a batchIterator into a storage.SeriesIterator. +// iteratorAdapter turns a batchIterator into a chunkenc.Iterator. // It fetches ever increasing batchSizes (up to promchunk.BatchSize) on each // call to Next; on calls to Seek, resets batch size to 1. type iteratorAdapter struct { @@ -81,15 +81,23 @@ func newIteratorAdapter(underlying iterator) chunkenc.Iterator { } } -// Seek implements storage.SeriesIterator. +// Seek implements chunkenc.Iterator. func (a *iteratorAdapter) Seek(t int64) bool { - // Optimisation: see if the seek is within the current batch. - if a.curr.Length > 0 && t >= a.curr.Timestamps[0] && t <= a.curr.Timestamps[a.curr.Length-1] { - a.curr.Index = 0 - for a.curr.Index < a.curr.Length && t > a.curr.Timestamps[a.curr.Index] { - a.curr.Index++ + + // Optimisation: fulfill the seek using current batch if possible. + if a.curr.Length > 0 && a.curr.Index < a.curr.Length { + if t <= a.curr.Timestamps[a.curr.Index] { + //In this case, the interface's requirement is met, so state of this + //iterator does not need any change. + return true + } else if t <= a.curr.Timestamps[a.curr.Length-1] { + //In this case, some timestamp between current sample and end of batch can fulfill + //the seek. Let's find it. + for a.curr.Index < a.curr.Length && t > a.curr.Timestamps[a.curr.Index] { + a.curr.Index++ + } + return true } - return true } a.curr.Length = -1 @@ -101,7 +109,7 @@ func (a *iteratorAdapter) Seek(t int64) bool { return false } -// Next implements storage.SeriesIterator. +// Next implements chunkenc.Iterator. func (a *iteratorAdapter) Next() bool { a.curr.Index++ for a.curr.Index >= a.curr.Length && a.underlying.Next(a.batchSize) { @@ -114,12 +122,12 @@ func (a *iteratorAdapter) Next() bool { return a.curr.Index < a.curr.Length } -// At implements storage.SeriesIterator. +// At implements chunkenc.Iterator. func (a *iteratorAdapter) At() (int64, float64) { return a.curr.Timestamps[a.curr.Index], a.curr.Values[a.curr.Index] } -// Err implements storage.SeriesIterator. +// Err implements chunkenc.Iterator. func (a *iteratorAdapter) Err() error { return nil } diff --git a/vendor/github.com/cortexproject/cortex/pkg/querier/batch/merge.go b/vendor/github.com/cortexproject/cortex/pkg/querier/batch/merge.go index 88220bd72735..7764b37467bd 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/querier/batch/merge.go +++ b/vendor/github.com/cortexproject/cortex/pkg/querier/batch/merge.go @@ -31,8 +31,8 @@ func newMergeIterator(cs []GenericChunk) *mergeIterator { c := &mergeIterator{ its: its, h: make(iteratorHeap, 0, len(its)), - batches: make(batchStream, 0, len(its)*2*promchunk.BatchSize), - batchesBuf: make(batchStream, len(its)*2*promchunk.BatchSize), + batches: make(batchStream, 0, len(its)), + batchesBuf: make(batchStream, len(its)), } for _, iter := range c.its { @@ -112,8 +112,7 @@ func (c *mergeIterator) buildNextBatch(size int) bool { for len(c.h) > 0 && (len(c.batches) == 0 || c.nextBatchEndTime() >= c.h[0].AtTime()) { c.nextBatchBuf[0] = c.h[0].Batch() c.batchesBuf = mergeStreams(c.batches, c.nextBatchBuf[:], c.batchesBuf, size) - copy(c.batches[:len(c.batchesBuf)], c.batchesBuf) - c.batches = c.batches[:len(c.batchesBuf)] + c.batches = append(c.batches[:0], c.batchesBuf...) if c.h[0].Next(size) { heap.Fix(&c.h, 0) diff --git a/vendor/github.com/cortexproject/cortex/pkg/querier/blocks_store_queryable.go b/vendor/github.com/cortexproject/cortex/pkg/querier/blocks_store_queryable.go index 6ed803010590..98cb61e14012 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/querier/blocks_store_queryable.go +++ b/vendor/github.com/cortexproject/cortex/pkg/querier/blocks_store_queryable.go @@ -616,7 +616,7 @@ func (q *blocksStoreQuerier) fetchSeriesFromStores( // Add series fingerprint to query limiter; will return error if we are over the limit limitErr := queryLimiter.AddSeries(cortexpb.FromLabelsToLabelAdapters(s.PromLabels())) if limitErr != nil { - return limitErr + return validation.LimitError(limitErr.Error()) } // Ensure the max number of chunks limit hasn't been reached (max == 0 means disabled). @@ -626,6 +626,16 @@ func (q *blocksStoreQuerier) fetchSeriesFromStores( return validation.LimitError(fmt.Sprintf(errMaxChunksPerQueryLimit, util.LabelMatchersToString(matchers), maxChunksLimit)) } } + chunksSize := 0 + for _, c := range s.Chunks { + chunksSize += c.Size() + } + if chunkBytesLimitErr := queryLimiter.AddChunkBytes(chunksSize); chunkBytesLimitErr != nil { + return validation.LimitError(chunkBytesLimitErr.Error()) + } + if chunkLimitErr := queryLimiter.AddChunks(len(s.Chunks)); chunkLimitErr != nil { + return validation.LimitError(chunkLimitErr.Error()) + } } if w := resp.GetWarning(); w != "" { diff --git a/vendor/github.com/cortexproject/cortex/pkg/querier/distributor_queryable.go b/vendor/github.com/cortexproject/cortex/pkg/querier/distributor_queryable.go index 5114b208e556..6b13b0a95d02 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/querier/distributor_queryable.go +++ b/vendor/github.com/cortexproject/cortex/pkg/querier/distributor_queryable.go @@ -7,6 +7,7 @@ import ( "github.com/go-kit/kit/log/level" "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/pkg/exemplar" "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/scrape" "github.com/prometheus/prometheus/storage" @@ -27,6 +28,7 @@ import ( type Distributor interface { Query(ctx context.Context, from, to model.Time, matchers ...*labels.Matcher) (model.Matrix, error) QueryStream(ctx context.Context, from, to model.Time, matchers ...*labels.Matcher) (*client.QueryStreamResponse, error) + QueryExemplars(ctx context.Context, from, to model.Time, matchers ...[]*labels.Matcher) (*client.ExemplarQueryResponse, error) LabelValuesForLabelName(ctx context.Context, from, to model.Time, label model.LabelName, matchers ...*labels.Matcher) ([]string, error) LabelNames(context.Context, model.Time, model.Time) ([]string, error) MetricsForLabelMatchers(ctx context.Context, from, through model.Time, matchers ...*labels.Matcher) ([]metric.Metric, error) @@ -198,3 +200,43 @@ func (q *distributorQuerier) LabelNames() ([]string, storage.Warnings, error) { func (q *distributorQuerier) Close() error { return nil } + +type distributorExemplarQueryable struct { + distributor Distributor +} + +func newDistributorExemplarQueryable(d Distributor) storage.ExemplarQueryable { + return &distributorExemplarQueryable{ + distributor: d, + } +} + +func (d distributorExemplarQueryable) ExemplarQuerier(ctx context.Context) (storage.ExemplarQuerier, error) { + return &distributorExemplarQuerier{ + distributor: d.distributor, + ctx: ctx, + }, nil +} + +type distributorExemplarQuerier struct { + distributor Distributor + ctx context.Context +} + +// Select querys for exemplars, prometheus' storage.ExemplarQuerier's Select function takes the time range as two int64 values. +func (q *distributorExemplarQuerier) Select(start, end int64, matchers ...[]*labels.Matcher) ([]exemplar.QueryResult, error) { + allResults, err := q.distributor.QueryExemplars(q.ctx, model.Time(start), model.Time(end), matchers...) + + if err != nil { + return nil, err + } + + var e exemplar.QueryResult + ret := make([]exemplar.QueryResult, len(allResults.Timeseries)) + for i, ts := range allResults.Timeseries { + e.SeriesLabels = cortexpb.FromLabelAdaptersToLabels(ts.Labels) + e.Exemplars = cortexpb.FromExemplarProtosToExemplars(ts.Exemplars) + ret[i] = e + } + return ret, nil +} diff --git a/vendor/github.com/cortexproject/cortex/pkg/api/queryable.go b/vendor/github.com/cortexproject/cortex/pkg/querier/error_translate_queryable.go similarity index 70% rename from vendor/github.com/cortexproject/cortex/pkg/api/queryable.go rename to vendor/github.com/cortexproject/cortex/pkg/querier/error_translate_queryable.go index 7629b3a34d50..97c1584d41c4 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/api/queryable.go +++ b/vendor/github.com/cortexproject/cortex/pkg/querier/error_translate_queryable.go @@ -1,4 +1,4 @@ -package api +package querier import ( "context" @@ -13,20 +13,26 @@ import ( "github.com/cortexproject/cortex/pkg/util/validation" ) -func translateError(err error) error { +// TranslateToPromqlAPIError converts error to one of promql.Errors for consumption in PromQL API. +// PromQL API only recognizes few errors, and converts everything else to HTTP status code 422. +// +// Specifically, it supports: +// +// promql.ErrQueryCanceled, mapped to 503 +// promql.ErrQueryTimeout, mapped to 503 +// promql.ErrStorage mapped to 500 +// anything else is mapped to 422 +// +// Querier code produces different kinds of errors, and we want to map them to above-mentioned HTTP status codes correctly. +// +// Details: +// - vendor/github.com/prometheus/prometheus/web/api/v1/api.go, respondError function only accepts *apiError types. +// - translation of error to *apiError happens in vendor/github.com/prometheus/prometheus/web/api/v1/api.go, returnAPIError method. +func TranslateToPromqlAPIError(err error) error { if err == nil { return err } - // vendor/github.com/prometheus/prometheus/web/api/v1/api.go, respondError function only accepts - // *apiError types. - // Translation of error to *apiError happens in vendor/github.com/prometheus/prometheus/web/api/v1/api.go, returnAPIError method. - // It only supports: - // promql.ErrQueryCanceled, mapped to 503 - // promql.ErrQueryTimeout, mapped to 503 - // promql.ErrStorage mapped to 500 - // anything else is mapped to 422 - switch errors.Cause(err).(type) { case promql.ErrStorage, promql.ErrTooManySamples, promql.ErrQueryCanceled, promql.ErrQueryTimeout: // Don't translate those, just in case we use them internally. @@ -63,18 +69,22 @@ func translateError(err error) error { } } +func NewErrorTranslateQueryable(q storage.SampleAndChunkQueryable) storage.SampleAndChunkQueryable { + return errorTranslateQueryable{q} +} + type errorTranslateQueryable struct { q storage.SampleAndChunkQueryable } func (e errorTranslateQueryable) Querier(ctx context.Context, mint, maxt int64) (storage.Querier, error) { q, err := e.q.Querier(ctx, mint, maxt) - return errorTranslateQuerier{q: q}, translateError(err) + return errorTranslateQuerier{q: q}, TranslateToPromqlAPIError(err) } func (e errorTranslateQueryable) ChunkQuerier(ctx context.Context, mint, maxt int64) (storage.ChunkQuerier, error) { q, err := e.q.ChunkQuerier(ctx, mint, maxt) - return errorTranslateChunkQuerier{q: q}, translateError(err) + return errorTranslateChunkQuerier{q: q}, TranslateToPromqlAPIError(err) } type errorTranslateQuerier struct { @@ -83,16 +93,16 @@ type errorTranslateQuerier struct { func (e errorTranslateQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]string, storage.Warnings, error) { values, warnings, err := e.q.LabelValues(name, matchers...) - return values, warnings, translateError(err) + return values, warnings, TranslateToPromqlAPIError(err) } func (e errorTranslateQuerier) LabelNames() ([]string, storage.Warnings, error) { values, warnings, err := e.q.LabelNames() - return values, warnings, translateError(err) + return values, warnings, TranslateToPromqlAPIError(err) } func (e errorTranslateQuerier) Close() error { - return translateError(e.q.Close()) + return TranslateToPromqlAPIError(e.q.Close()) } func (e errorTranslateQuerier) Select(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet { @@ -106,16 +116,16 @@ type errorTranslateChunkQuerier struct { func (e errorTranslateChunkQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]string, storage.Warnings, error) { values, warnings, err := e.q.LabelValues(name, matchers...) - return values, warnings, translateError(err) + return values, warnings, TranslateToPromqlAPIError(err) } func (e errorTranslateChunkQuerier) LabelNames() ([]string, storage.Warnings, error) { values, warnings, err := e.q.LabelNames() - return values, warnings, translateError(err) + return values, warnings, TranslateToPromqlAPIError(err) } func (e errorTranslateChunkQuerier) Close() error { - return translateError(e.q.Close()) + return TranslateToPromqlAPIError(e.q.Close()) } func (e errorTranslateChunkQuerier) Select(sortSeries bool, hints *storage.SelectHints, matchers ...*labels.Matcher) storage.ChunkSeriesSet { @@ -136,7 +146,7 @@ func (e errorTranslateSeriesSet) At() storage.Series { } func (e errorTranslateSeriesSet) Err() error { - return translateError(e.s.Err()) + return TranslateToPromqlAPIError(e.s.Err()) } func (e errorTranslateSeriesSet) Warnings() storage.Warnings { @@ -156,7 +166,7 @@ func (e errorTranslateChunkSeriesSet) At() storage.ChunkSeries { } func (e errorTranslateChunkSeriesSet) Err() error { - return translateError(e.s.Err()) + return TranslateToPromqlAPIError(e.s.Err()) } func (e errorTranslateChunkSeriesSet) Warnings() storage.Warnings { diff --git a/vendor/github.com/cortexproject/cortex/pkg/querier/iterators/chunk_merge_iterator.go b/vendor/github.com/cortexproject/cortex/pkg/querier/iterators/chunk_merge_iterator.go index 1d2e301e03f0..c056fa209308 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/querier/iterators/chunk_merge_iterator.go +++ b/vendor/github.com/cortexproject/cortex/pkg/querier/iterators/chunk_merge_iterator.go @@ -19,7 +19,7 @@ type chunkMergeIterator struct { currErr error } -// NewChunkMergeIterator creates a storage.SeriesIterator for a set of chunks. +// NewChunkMergeIterator creates a chunkenc.Iterator for a set of chunks. func NewChunkMergeIterator(cs []chunk.Chunk, _, _ model.Time) chunkenc.Iterator { its := buildIterators(cs) c := &chunkMergeIterator{ diff --git a/vendor/github.com/cortexproject/cortex/pkg/querier/querier.go b/vendor/github.com/cortexproject/cortex/pkg/querier/querier.go index 3bd89a767f45..cb3b35f32e05 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/querier/querier.go +++ b/vendor/github.com/cortexproject/cortex/pkg/querier/querier.go @@ -144,7 +144,7 @@ func NewChunkStoreQueryable(cfg Config, chunkStore chunkstore.ChunkStore) storag } // New builds a queryable and promql engine. -func New(cfg Config, limits *validation.Overrides, distributor Distributor, stores []QueryableWithFilter, tombstonesLoader *purger.TombstonesLoader, reg prometheus.Registerer, logger log.Logger) (storage.SampleAndChunkQueryable, *promql.Engine) { +func New(cfg Config, limits *validation.Overrides, distributor Distributor, stores []QueryableWithFilter, tombstonesLoader *purger.TombstonesLoader, reg prometheus.Registerer, logger log.Logger) (storage.SampleAndChunkQueryable, storage.ExemplarQueryable, *promql.Engine) { iteratorFunc := getChunksIteratorFunction(cfg) distributorQueryable := newDistributorQueryable(distributor, cfg.IngesterStreaming, iteratorFunc, cfg.QueryIngestersWithin) @@ -157,6 +157,7 @@ func New(cfg Config, limits *validation.Overrides, distributor Distributor, stor } } queryable := NewQueryable(distributorQueryable, ns, iteratorFunc, cfg, limits, tombstonesLoader) + exemplarQueryable := newDistributorExemplarQueryable(distributor) lazyQueryable := storage.QueryableFunc(func(ctx context.Context, mint int64, maxt int64) (storage.Querier, error) { querier, err := queryable.Querier(ctx, mint, maxt) @@ -178,7 +179,7 @@ func New(cfg Config, limits *validation.Overrides, distributor Distributor, stor return cfg.DefaultEvaluationInterval.Milliseconds() }, }) - return NewSampleAndChunkQueryable(lazyQueryable), engine + return NewSampleAndChunkQueryable(lazyQueryable), exemplarQueryable, engine } // NewSampleAndChunkQueryable creates a SampleAndChunkQueryable from a @@ -224,7 +225,7 @@ func NewQueryable(distributor QueryableWithFilter, stores []QueryableWithFilter, return nil, err } - ctx = limiter.AddQueryLimiterToContext(ctx, limiter.NewQueryLimiter(limits.MaxFetchedSeriesPerQuery(userID))) + ctx = limiter.AddQueryLimiterToContext(ctx, limiter.NewQueryLimiter(limits.MaxFetchedSeriesPerQuery(userID), limits.MaxFetchedChunkBytesPerQuery(userID), limits.MaxChunksPerQuery(userID))) mint, maxt, err = validateQueryTimeRange(ctx, userID, mint, maxt, limits, cfg.MaxQueryIntoFuture) if err == errEmptyTimeRange { diff --git a/vendor/github.com/cortexproject/cortex/pkg/querier/tenantfederation/merge_queryable.go b/vendor/github.com/cortexproject/cortex/pkg/querier/tenantfederation/merge_queryable.go index c05f99801710..fa1f5ce72725 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/querier/tenantfederation/merge_queryable.go +++ b/vendor/github.com/cortexproject/cortex/pkg/querier/tenantfederation/merge_queryable.go @@ -139,8 +139,17 @@ type mergeQuerier struct { func (m *mergeQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]string, storage.Warnings, error) { log, _ := spanlogger.New(m.ctx, "mergeQuerier.LabelValues") defer log.Span.Finish() + + matchedTenants, filteredMatchers := filterValuesByMatchers(m.idLabelName, m.ids, matchers...) + if name == m.idLabelName { - return m.ids, nil, nil + var labelValues = make([]string, 0, len(matchedTenants)) + for _, id := range m.ids { + if _, matched := matchedTenants[id]; matched { + labelValues = append(labelValues, id) + } + } + return labelValues, nil, nil } // ensure the name of a retained label gets handled under the original @@ -149,9 +158,9 @@ func (m *mergeQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([] name = m.idLabelName } - return m.mergeDistinctStringSlice(func(ctx context.Context, q storage.Querier) ([]string, storage.Warnings, error) { - return q.LabelValues(name, matchers...) - }) + return m.mergeDistinctStringSliceWithTenants(func(ctx context.Context, q storage.Querier) ([]string, storage.Warnings, error) { + return q.LabelValues(name, filteredMatchers...) + }, matchedTenants) } // LabelNames returns all the unique label names present in the underlying @@ -200,18 +209,25 @@ type stringSliceFuncJob struct { warnings storage.Warnings } -// mergeDistinctStringSlice is aggregating results from stringSliceFunc calls -// on per querier in parallel. It removes duplicates and sorts the result. It -// doesn't require the output of the stringSliceFunc to be sorted, as results +// mergeDistinctStringSliceWithTenants aggregates stringSliceFunc call +// results from queriers whose tenant ids match the tenants map. If a nil map is +// provided, all queriers are used. It removes duplicates and sorts the result. +// It doesn't require the output of the stringSliceFunc to be sorted, as results // of LabelValues are not sorted. -func (m *mergeQuerier) mergeDistinctStringSlice(f stringSliceFunc) ([]string, storage.Warnings, error) { - var jobs = make([]interface{}, len(m.ids)) +func (m *mergeQuerier) mergeDistinctStringSliceWithTenants(f stringSliceFunc, tenants map[string]struct{}) ([]string, storage.Warnings, error) { + var jobs []interface{} + + for pos, id := range m.ids { + if tenants != nil { + if _, matched := tenants[id]; !matched { + continue + } + } - for pos := range m.ids { - jobs[pos] = &stringSliceFuncJob{ + jobs = append(jobs, &stringSliceFuncJob{ querier: m.queriers[pos], id: m.ids[pos], - } + }) } run := func(ctx context.Context, jobIntf interface{}) error { @@ -260,6 +276,12 @@ func (m *mergeQuerier) mergeDistinctStringSlice(f stringSliceFunc) ([]string, st return result, warnings, nil } +// mergeDistinctStringSlice aggregates results from all stringSliceFunc calls +// for all queriers, in parallel. +func (m *mergeQuerier) mergeDistinctStringSlice(f stringSliceFunc) ([]string, storage.Warnings, error) { + return m.mergeDistinctStringSliceWithTenants(f, nil) +} + // Close releases the resources of the Querier. func (m *mergeQuerier) Close() error { errs := tsdb_errors.NewMulti() diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/basic_lifecycler.go b/vendor/github.com/cortexproject/cortex/pkg/ring/basic_lifecycler.go index 6c19d72c281e..64f5f6002c44 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/basic_lifecycler.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/basic_lifecycler.go @@ -13,6 +13,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/cortexproject/cortex/pkg/ring/kv" + "github.com/cortexproject/cortex/pkg/util" util_log "github.com/cortexproject/cortex/pkg/util/log" "github.com/cortexproject/cortex/pkg/util/services" ) @@ -182,12 +183,12 @@ func (l *BasicLifecycler) starting(ctx context.Context) error { } func (l *BasicLifecycler) running(ctx context.Context) error { - heartbeatTicker := time.NewTicker(l.cfg.HeartbeatPeriod) - defer heartbeatTicker.Stop() + heartbeatTickerStop, heartbeatTickerChan := util.NewDisableableTicker(l.cfg.HeartbeatPeriod) + defer heartbeatTickerStop() for { select { - case <-heartbeatTicker.C: + case <-heartbeatTickerChan: l.heartbeat(ctx) case f := <-l.actorChan: @@ -214,13 +215,13 @@ func (l *BasicLifecycler) stopping(runningError error) error { }() // Heartbeat while the stopping delegate function is running. - heartbeatTicker := time.NewTicker(l.cfg.HeartbeatPeriod) - defer heartbeatTicker.Stop() + heartbeatTickerStop, heartbeatTickerChan := util.NewDisableableTicker(l.cfg.HeartbeatPeriod) + defer heartbeatTickerStop() heartbeatLoop: for { select { - case <-heartbeatTicker.C: + case <-heartbeatTickerChan: l.heartbeat(context.Background()) case <-done: break heartbeatLoop @@ -292,8 +293,8 @@ func (l *BasicLifecycler) registerInstance(ctx context.Context) error { } func (l *BasicLifecycler) waitStableTokens(ctx context.Context, period time.Duration) error { - heartbeatTicker := time.NewTicker(l.cfg.HeartbeatPeriod) - defer heartbeatTicker.Stop() + heartbeatTickerStop, heartbeatTickerChan := util.NewDisableableTicker(l.cfg.HeartbeatPeriod) + defer heartbeatTickerStop() // The first observation will occur after the specified period. level.Info(l.logger).Log("msg", "waiting stable tokens", "ring", l.ringName) @@ -312,7 +313,7 @@ func (l *BasicLifecycler) waitStableTokens(ctx context.Context, period time.Dura level.Info(l.logger).Log("msg", "tokens verification succeeded", "ring", l.ringName) return nil - case <-heartbeatTicker.C: + case <-heartbeatTickerChan: l.heartbeat(ctx) case <-ctx.Done(): diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/etcd/etcd.go b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/etcd/etcd.go index d981c00320ad..34999ab37129 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/etcd/etcd.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/etcd/etcd.go @@ -26,6 +26,9 @@ type Config struct { MaxRetries int `yaml:"max_retries"` EnableTLS bool `yaml:"tls_enabled"` TLS cortex_tls.ClientConfig `yaml:",inline"` + + UserName string `yaml:"username"` + Password string `yaml:"password"` } // Client implements ring.KVClient for etcd. @@ -42,6 +45,8 @@ func (cfg *Config) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix string) { f.DurationVar(&cfg.DialTimeout, prefix+"etcd.dial-timeout", 10*time.Second, "The dial timeout for the etcd connection.") f.IntVar(&cfg.MaxRetries, prefix+"etcd.max-retries", 10, "The maximum number of retries to do for failed ops.") f.BoolVar(&cfg.EnableTLS, prefix+"etcd.tls-enabled", false, "Enable TLS.") + f.StringVar(&cfg.UserName, prefix+"etcd.username", "", "Etcd username.") + f.StringVar(&cfg.Password, prefix+"etcd.password", "", "Etcd password.") cfg.TLS.RegisterFlagsWithPrefix(prefix+"etcd", f) } @@ -87,6 +92,8 @@ func New(cfg Config, codec codec.Codec) (*Client, error) { DialKeepAliveTimeout: 2 * cfg.DialTimeout, PermitWithoutStream: true, TLS: tlsConfig, + Username: cfg.UserName, + Password: cfg.Password, }) if err != nil { return nil, err diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/kv_init_service.go b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/kv_init_service.go index da4d965b7c94..517c6742819e 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/kv_init_service.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/kv_init_service.go @@ -16,7 +16,6 @@ import ( "github.com/hashicorp/memberlist" "go.uber.org/atomic" - "github.com/cortexproject/cortex/pkg/ring/kv/codec" "github.com/cortexproject/cortex/pkg/util" "github.com/cortexproject/cortex/pkg/util/services" ) @@ -106,12 +105,12 @@ func (kvs *KVInitService) ServeHTTP(w http.ResponseWriter, req *http.Request) { if err := req.ParseForm(); err == nil { if req.Form[downloadKeyParam] != nil { - downloadKey(w, kv.storeCopy(), req.Form[downloadKeyParam][0]) // Use first value, ignore the rest. + downloadKey(w, kv, kv.storeCopy(), req.Form[downloadKeyParam][0]) // Use first value, ignore the rest. return } if req.Form[viewKeyParam] != nil { - viewKey(w, kv, kv.storeCopy(), req.Form[viewKeyParam][0], getFormat(req)) + viewKey(w, kv.storeCopy(), req.Form[viewKeyParam][0], getFormat(req)) return } @@ -179,30 +178,25 @@ func viewMessage(w http.ResponseWriter, kv *KV, msg message, format string) { return } - formatValue(w, c, msg.Pair.Value, format) + val, err := c.Decode(msg.Pair.Value) + if err != nil { + http.Error(w, fmt.Sprintf("failed to decode: %v", err), http.StatusInternalServerError) + return + } + + formatValue(w, val, format) } -func viewKey(w http.ResponseWriter, kv *KV, store map[string]valueDesc, key string, format string) { +func viewKey(w http.ResponseWriter, store map[string]valueDesc, key string, format string) { if store[key].value == nil { http.Error(w, "value not found", http.StatusNotFound) return } - c := kv.GetCodec(store[key].codecID) - if c == nil { - http.Error(w, "codec not found", http.StatusNotFound) - return - } - - formatValue(w, c, store[key].value, format) + formatValue(w, store[key].value, format) } -func formatValue(w http.ResponseWriter, codec codec.Codec, value []byte, format string) { - val, err := codec.Decode(value) - if err != nil { - http.Error(w, fmt.Sprintf("failed to decode: %v", err), http.StatusInternalServerError) - return - } +func formatValue(w http.ResponseWriter, val interface{}, format string) { w.WriteHeader(200) w.Header().Add("content-type", "text/plain") @@ -214,7 +208,7 @@ func formatValue(w http.ResponseWriter, codec codec.Codec, value []byte, format enc.SetIndent("", " ") } - err = enc.Encode(val) + err := enc.Encode(val) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } @@ -224,7 +218,7 @@ func formatValue(w http.ResponseWriter, codec codec.Codec, value []byte, format } } -func downloadKey(w http.ResponseWriter, store map[string]valueDesc, key string) { +func downloadKey(w http.ResponseWriter, kv *KV, store map[string]valueDesc, key string) { if store[key].value == nil { http.Error(w, "value not found", http.StatusNotFound) return @@ -232,14 +226,26 @@ func downloadKey(w http.ResponseWriter, store map[string]valueDesc, key string) val := store[key] + c := kv.GetCodec(store[key].codecID) + if c == nil { + http.Error(w, "codec not found", http.StatusNotFound) + return + } + + encoded, err := c.Encode(val.value) + if err != nil { + http.Error(w, fmt.Sprintf("failed to encode: %v", err), http.StatusInternalServerError) + return + } + w.Header().Add("content-type", "application/octet-stream") // Set content-length so that client knows whether it has received full response or not. - w.Header().Add("content-length", strconv.Itoa(len(val.value))) + w.Header().Add("content-length", strconv.Itoa(len(encoded))) w.Header().Add("content-disposition", fmt.Sprintf("attachment; filename=%d-%s", val.version, key)) w.WriteHeader(200) // Ignore errors, we cannot do anything about them. - _, _ = w.Write(val.value) + _, _ = w.Write(encoded) } type pageData struct { diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/memberlist_client.go b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/memberlist_client.go index 056cc7817187..79432d4668df 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/memberlist_client.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/memberlist_client.go @@ -136,6 +136,7 @@ type KVConfig struct { GossipNodes int `yaml:"gossip_nodes"` GossipToTheDeadTime time.Duration `yaml:"gossip_to_dead_nodes_time"` DeadNodeReclaimTime time.Duration `yaml:"dead_node_reclaim_time"` + EnableCompression bool `yaml:"compression_enabled"` // List of members to join JoinMembers flagext.StringSlice `yaml:"join_members"` @@ -165,12 +166,14 @@ type KVConfig struct { } // RegisterFlags registers flags. -func (cfg *KVConfig) RegisterFlags(f *flag.FlagSet, prefix string) { +func (cfg *KVConfig) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix string) { + mlDefaults := defaultMemberlistConfig() + // "Defaults to hostname" -- memberlist sets it to hostname by default. f.StringVar(&cfg.NodeName, prefix+"memberlist.nodename", "", "Name of the node in memberlist cluster. Defaults to hostname.") // memberlist.DefaultLANConfig will put hostname here. f.BoolVar(&cfg.RandomizeNodeName, prefix+"memberlist.randomize-node-name", true, "Add random suffix to the node name.") - f.DurationVar(&cfg.StreamTimeout, prefix+"memberlist.stream-timeout", 0, "The timeout for establishing a connection with a remote node, and for read/write operations. Uses memberlist LAN defaults if 0.") - f.IntVar(&cfg.RetransmitMult, prefix+"memberlist.retransmit-factor", 0, "Multiplication factor used when sending out messages (factor * log(N+1)).") + f.DurationVar(&cfg.StreamTimeout, prefix+"memberlist.stream-timeout", mlDefaults.TCPTimeout, "The timeout for establishing a connection with a remote node, and for read/write operations.") + f.IntVar(&cfg.RetransmitMult, prefix+"memberlist.retransmit-factor", mlDefaults.RetransmitMult, "Multiplication factor used when sending out messages (factor * log(N+1)).") f.Var(&cfg.JoinMembers, prefix+"memberlist.join", "Other cluster members to join. Can be specified multiple times. It can be an IP, hostname or an entry specified in the DNS Service Discovery format (see https://cortexmetrics.io/docs/configuration/arguments/#dns-service-discovery for more details).") f.DurationVar(&cfg.MinJoinBackoff, prefix+"memberlist.min-join-backoff", 1*time.Second, "Min backoff duration to join other cluster members.") f.DurationVar(&cfg.MaxJoinBackoff, prefix+"memberlist.max-join-backoff", 1*time.Minute, "Max backoff duration to join other cluster members.") @@ -179,16 +182,21 @@ func (cfg *KVConfig) RegisterFlags(f *flag.FlagSet, prefix string) { f.DurationVar(&cfg.RejoinInterval, prefix+"memberlist.rejoin-interval", 0, "If not 0, how often to rejoin the cluster. Occasional rejoin can help to fix the cluster split issue, and is harmless otherwise. For example when using only few components as a seed nodes (via -memberlist.join), then it's recommended to use rejoin. If -memberlist.join points to dynamic service that resolves to all gossiping nodes (eg. Kubernetes headless service), then rejoin is not needed.") f.DurationVar(&cfg.LeftIngestersTimeout, prefix+"memberlist.left-ingesters-timeout", 5*time.Minute, "How long to keep LEFT ingesters in the ring.") f.DurationVar(&cfg.LeaveTimeout, prefix+"memberlist.leave-timeout", 5*time.Second, "Timeout for leaving memberlist cluster.") - f.DurationVar(&cfg.GossipInterval, prefix+"memberlist.gossip-interval", 0, "How often to gossip. Uses memberlist LAN defaults if 0.") - f.IntVar(&cfg.GossipNodes, prefix+"memberlist.gossip-nodes", 0, "How many nodes to gossip to. Uses memberlist LAN defaults if 0.") - f.DurationVar(&cfg.PushPullInterval, prefix+"memberlist.pullpush-interval", 0, "How often to use pull/push sync. Uses memberlist LAN defaults if 0.") - f.DurationVar(&cfg.GossipToTheDeadTime, prefix+"memberlist.gossip-to-dead-nodes-time", 0, "How long to keep gossiping to dead nodes, to give them chance to refute their death. Uses memberlist LAN defaults if 0.") - f.DurationVar(&cfg.DeadNodeReclaimTime, prefix+"memberlist.dead-node-reclaim-time", 0, "How soon can dead node's name be reclaimed with new address. Defaults to 0, which is disabled.") + f.DurationVar(&cfg.GossipInterval, prefix+"memberlist.gossip-interval", mlDefaults.GossipInterval, "How often to gossip.") + f.IntVar(&cfg.GossipNodes, prefix+"memberlist.gossip-nodes", mlDefaults.GossipNodes, "How many nodes to gossip to.") + f.DurationVar(&cfg.PushPullInterval, prefix+"memberlist.pullpush-interval", mlDefaults.PushPullInterval, "How often to use pull/push sync.") + f.DurationVar(&cfg.GossipToTheDeadTime, prefix+"memberlist.gossip-to-dead-nodes-time", mlDefaults.GossipToTheDeadTime, "How long to keep gossiping to dead nodes, to give them chance to refute their death.") + f.DurationVar(&cfg.DeadNodeReclaimTime, prefix+"memberlist.dead-node-reclaim-time", mlDefaults.DeadNodeReclaimTime, "How soon can dead node's name be reclaimed with new address. 0 to disable.") f.IntVar(&cfg.MessageHistoryBufferBytes, prefix+"memberlist.message-history-buffer-bytes", 0, "How much space to use for keeping received and sent messages in memory for troubleshooting (two buffers). 0 to disable.") + f.BoolVar(&cfg.EnableCompression, prefix+"memberlist.compression-enabled", mlDefaults.EnableCompression, "Enable message compression. This can be used to reduce bandwidth usage at the cost of slightly more CPU utilization.") cfg.TCPTransport.RegisterFlags(f, prefix) } +func (cfg *KVConfig) RegisterFlags(f *flag.FlagSet) { + cfg.RegisterFlagsWithPrefix(f, "") +} + func generateRandomSuffix() string { suffix := make([]byte, 4) _, err := rand.Read(suffix) @@ -252,13 +260,15 @@ type KV struct { totalSizeOfPushes prometheus.Counter numberOfBroadcastMessagesInQueue prometheus.GaugeFunc totalSizeOfBroadcastMessagesInQueue prometheus.Gauge + numberOfBroadcastMessagesDropped prometheus.Counter casAttempts prometheus.Counter casFailures prometheus.Counter casSuccesses prometheus.Counter watchPrefixDroppedNotifications *prometheus.CounterVec - storeValuesDesc *prometheus.Desc - storeSizesDesc *prometheus.Desc + storeValuesDesc *prometheus.Desc + storeTombstones *prometheus.GaugeVec + storeRemovedTombstones *prometheus.CounterVec memberlistMembersCount prometheus.GaugeFunc memberlistHealthScore prometheus.GaugeFunc @@ -283,9 +293,11 @@ type message struct { } type valueDesc struct { - // We store bytes here. Reason is that clients calling CAS function will modify the object in place, - // but unless CAS succeeds, we don't want those modifications to be visible. - value []byte + // We store the decoded value here to prevent decoding the entire state for every + // update we receive. Whilst the updates are small and fast to decode, + // the total state can be quite large. + // The CAS function is passed a deep copy because it modifies in-place. + value Mergeable // version (local only) is used to keep track of what we're gossiping about, and invalidate old messages version uint @@ -294,8 +306,16 @@ type valueDesc struct { codecID string } +func (v valueDesc) Clone() (result valueDesc) { + result = v + if v.value != nil { + result.value = v.value.Clone() + } + return +} + func (v valueDesc) String() string { - return fmt.Sprintf("size: %d, version: %d, codec: %s", len(v.value), v.version, v.codecID) + return fmt.Sprintf("version: %d, codec: %s", v.version, v.codecID) } var ( @@ -342,36 +362,28 @@ func NewKV(cfg KVConfig, logger log.Logger) *KV { return mlkv } +func defaultMemberlistConfig() *memberlist.Config { + return memberlist.DefaultLANConfig() +} + func (m *KV) buildMemberlistConfig() (*memberlist.Config, error) { tr, err := NewTCPTransport(m.cfg.TCPTransport, m.logger) if err != nil { return nil, fmt.Errorf("failed to create transport: %v", err) } - mlCfg := memberlist.DefaultLANConfig() + mlCfg := defaultMemberlistConfig() mlCfg.Delegate = m - if m.cfg.StreamTimeout != 0 { - mlCfg.TCPTimeout = m.cfg.StreamTimeout - } - if m.cfg.RetransmitMult != 0 { - mlCfg.RetransmitMult = m.cfg.RetransmitMult - } - if m.cfg.PushPullInterval != 0 { - mlCfg.PushPullInterval = m.cfg.PushPullInterval - } - if m.cfg.GossipInterval != 0 { - mlCfg.GossipInterval = m.cfg.GossipInterval - } - if m.cfg.GossipNodes != 0 { - mlCfg.GossipNodes = m.cfg.GossipNodes - } - if m.cfg.GossipToTheDeadTime > 0 { - mlCfg.GossipToTheDeadTime = m.cfg.GossipToTheDeadTime - } - if m.cfg.DeadNodeReclaimTime > 0 { - mlCfg.DeadNodeReclaimTime = m.cfg.DeadNodeReclaimTime - } + mlCfg.TCPTimeout = m.cfg.StreamTimeout + mlCfg.RetransmitMult = m.cfg.RetransmitMult + mlCfg.PushPullInterval = m.cfg.PushPullInterval + mlCfg.GossipInterval = m.cfg.GossipInterval + mlCfg.GossipNodes = m.cfg.GossipNodes + mlCfg.GossipToTheDeadTime = m.cfg.GossipToTheDeadTime + mlCfg.DeadNodeReclaimTime = m.cfg.DeadNodeReclaimTime + mlCfg.EnableCompression = m.cfg.EnableCompression + if m.cfg.NodeName != "" { mlCfg.Name = m.cfg.NodeName } @@ -412,7 +424,7 @@ func (m *KV) starting(_ context.Context) error { m.memberlist = list m.broadcasts = &memberlist.TransmitLimitedQueue{ NumNodes: list.NumMembers, - RetransmitMult: m.cfg.RetransmitMult, + RetransmitMult: mlCfg.RetransmitMult, } m.initWG.Done() @@ -612,24 +624,16 @@ func (m *KV) Get(key string, codec codec.Codec) (interface{}, error) { // Returns current value with removed tombstones. func (m *KV) get(key string, codec codec.Codec) (out interface{}, version uint, err error) { m.storeMu.Lock() - v := m.store[key] + v := m.store[key].Clone() m.storeMu.Unlock() - out = nil if v.value != nil { - out, err = codec.Decode(v.value) - if err != nil { - return nil, 0, err - } - - if mr, ok := out.(Mergeable); ok { - // remove ALL tombstones before returning to client. - // No need for clients to see them. - mr.RemoveTombstones(time.Time{}) - } + // remove ALL tombstones before returning to client. + // No need for clients to see them. + _, _ = v.value.RemoveTombstones(time.Time{}) } - return out, v.version, nil + return v.value, v.version, nil } // WatchKey watches for value changes for given key. When value changes, 'f' function is called with the @@ -883,14 +887,17 @@ func (m *KV) trySingleCas(key string, codec codec.Codec, f func(in interface{}) func (m *KV) broadcastNewValue(key string, change Mergeable, version uint, codec codec.Codec) { data, err := codec.Encode(change) if err != nil { - level.Error(m.logger).Log("msg", "failed to encode change", "err", err) + level.Error(m.logger).Log("msg", "failed to encode change", "key", key, "version", version, "err", err) + m.numberOfBroadcastMessagesDropped.Inc() return } kvPair := KeyValuePair{Key: key, Value: data, Codec: codec.CodecID()} pairData, err := kvPair.Marshal() if err != nil { - level.Error(m.logger).Log("msg", "failed to serialize KV pair", "err", err) + level.Error(m.logger).Log("msg", "failed to serialize KV pair", "key", key, "version", version, "err", err) + m.numberOfBroadcastMessagesDropped.Inc() + return } if len(pairData) > 65535 { @@ -900,7 +907,8 @@ func (m *KV) broadcastNewValue(key string, change Mergeable, version uint, codec // // Typically messages are smaller (when dealing with couple of updates only), but can get bigger // when broadcasting result of push/pull update. - level.Debug(m.logger).Log("msg", "broadcast message too big, not broadcasting", "len", len(pairData)) + level.Debug(m.logger).Log("msg", "broadcast message too big, not broadcasting", "key", key, "version", version, "len", len(pairData)) + m.numberOfBroadcastMessagesDropped.Inc() return } @@ -1039,9 +1047,21 @@ func (m *KV) LocalState(join bool) []byte { continue } + codec := m.GetCodec(val.codecID) + if codec == nil { + level.Error(m.logger).Log("msg", "failed to encode remote state: unknown codec for key", "codec", val.codecID, "key", key) + continue + } + + encoded, err := codec.Encode(val.value) + if err != nil { + level.Error(m.logger).Log("msg", "failed to encode remote state", "err", err) + continue + } + kvPair.Reset() kvPair.Key = key - kvPair.Value = val.value + kvPair.Value = encoded kvPair.Codec = val.codecID ser, err := kvPair.Marshal() @@ -1051,7 +1071,7 @@ func (m *KV) LocalState(join bool) []byte { } if uint(len(ser)) > math.MaxUint32 { - level.Error(m.logger).Log("msg", "value too long", "key", key, "value_length", len(val.value)) + level.Error(m.logger).Log("msg", "value too long", "key", key, "value_length", len(encoded)) continue } @@ -1173,12 +1193,12 @@ func (m *KV) mergeValueForKey(key string, incomingValue Mergeable, casVersion ui m.storeMu.Lock() defer m.storeMu.Unlock() - curr := m.store[key] + curr := m.store[key].Clone() // if casVersion is 0, then there was no previous value, so we will just do normal merge, without localCAS flag set. if casVersion > 0 && curr.version != casVersion { return nil, 0, errVersionMismatch } - result, change, err := computeNewValue(incomingValue, curr.value, codec, casVersion > 0) + result, change, err := computeNewValue(incomingValue, curr.value, casVersion > 0) if err != nil { return nil, 0, err } @@ -1190,17 +1210,14 @@ func (m *KV) mergeValueForKey(key string, incomingValue Mergeable, casVersion ui if m.cfg.LeftIngestersTimeout > 0 { limit := time.Now().Add(-m.cfg.LeftIngestersTimeout) - result.RemoveTombstones(limit) - } - - encoded, err := codec.Encode(result) - if err != nil { - return nil, 0, fmt.Errorf("failed to encode merged result: %v", err) + total, removed := result.RemoveTombstones(limit) + m.storeTombstones.WithLabelValues(key).Set(float64(total)) + m.storeRemovedTombstones.WithLabelValues(key).Add(float64(removed)) } newVersion := curr.version + 1 m.store[key] = valueDesc{ - value: encoded, + value: result, version: newVersion, codecID: codec.CodecID(), } @@ -1209,25 +1226,7 @@ func (m *KV) mergeValueForKey(key string, incomingValue Mergeable, casVersion ui } // returns [result, change, error] -func computeNewValue(incoming Mergeable, stored []byte, c codec.Codec, cas bool) (Mergeable, Mergeable, error) { - if len(stored) == 0 { - return incoming, incoming, nil - } - - old, err := c.Decode(stored) - if err != nil { - return incoming, incoming, fmt.Errorf("failed to decode stored value: %v", err) - } - - if old == nil { - return incoming, incoming, nil - } - - oldVal, ok := old.(Mergeable) - if !ok { - return incoming, incoming, fmt.Errorf("stored value is not Mergeable, got %T", old) - } - +func computeNewValue(incoming Mergeable, oldVal Mergeable, cas bool) (Mergeable, Mergeable, error) { if oldVal == nil { return incoming, incoming, nil } @@ -1243,7 +1242,7 @@ func (m *KV) storeCopy() map[string]valueDesc { result := make(map[string]valueDesc, len(m.store)) for k, v := range m.store { - result[k] = v + result[k] = v.Clone() } return result } diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/mergeable.go b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/mergeable.go index 36866c5e9ce2..a013e3498809 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/mergeable.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/mergeable.go @@ -38,5 +38,9 @@ type Mergeable interface { // Remove tombstones older than given limit from this mergeable. // If limit is zero time, remove all tombstones. Memberlist client calls this method with zero limit each // time when client is accessing value from the store. It can be used to hide tombstones from the clients. - RemoveTombstones(limit time.Time) + // Returns the total number of tombstones present and the number of removed tombstones by this invocation. + RemoveTombstones(limit time.Time) (total, removed int) + + // Clone should return a deep copy of the state. + Clone() Mergeable } diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/metrics.go b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/metrics.go index 2cbcb6b15a98..e6e7d9bb4df7 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/metrics.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/kv/memberlist/metrics.go @@ -84,6 +84,13 @@ func (m *KV) createAndRegisterMetrics() { Help: "Total size of messages waiting in the broadcast queue", }) + m.numberOfBroadcastMessagesDropped = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: m.cfg.MetricsNamespace, + Subsystem: subsystem, + Name: "messages_to_broadcast_dropped_total", + Help: "Number of broadcast messages intended to be sent but were dropped due to encoding errors or for being too big", + }) + m.casAttempts = prometheus.NewCounter(prometheus.CounterOpts{ Namespace: m.cfg.MetricsNamespace, Subsystem: subsystem, @@ -110,10 +117,19 @@ func (m *KV) createAndRegisterMetrics() { "Number of values in KV Store", nil, nil) - m.storeSizesDesc = prometheus.NewDesc( - prometheus.BuildFQName(m.cfg.MetricsNamespace, subsystem, "kv_store_value_bytes"), // gauge - "Sizes of values in KV Store in bytes", - []string{"key"}, nil) + m.storeTombstones = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: m.cfg.MetricsNamespace, + Subsystem: subsystem, + Name: "kv_store_value_tombstones", + Help: "Number of tombstones currently present in KV store values", + }, []string{"key"}) + + m.storeRemovedTombstones = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: m.cfg.MetricsNamespace, + Subsystem: subsystem, + Name: "kv_store_value_tombstones_removed_total", + Help: "Total number of tombstones which have been removed from KV store values", + }, []string{"key"}) m.memberlistMembersCount = prometheus.NewGaugeFunc(prometheus.GaugeOpts{ Namespace: m.cfg.MetricsNamespace, @@ -162,10 +178,13 @@ func (m *KV) createAndRegisterMetrics() { m.totalSizeOfPushes, m.totalSizeOfPulls, m.totalSizeOfBroadcastMessagesInQueue, + m.numberOfBroadcastMessagesDropped, m.casAttempts, m.casFailures, m.casSuccesses, m.watchPrefixDroppedNotifications, + m.storeTombstones, + m.storeRemovedTombstones, m.memberlistMembersCount, m.memberlistHealthScore, } @@ -198,7 +217,6 @@ func (m *KV) createAndRegisterMetrics() { // Describe returns prometheus descriptions via supplied channel func (m *KV) Describe(ch chan<- *prometheus.Desc) { ch <- m.storeValuesDesc - ch <- m.storeSizesDesc } // Collect returns extra metrics via supplied channel @@ -207,8 +225,4 @@ func (m *KV) Collect(ch chan<- prometheus.Metric) { defer m.storeMu.Unlock() ch <- prometheus.MustNewConstMetric(m.storeValuesDesc, prometheus.GaugeValue, float64(len(m.store))) - - for k, v := range m.store { - ch <- prometheus.MustNewConstMetric(m.storeSizesDesc, prometheus.GaugeValue, float64(len(v.value)), k) - } } diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/lifecycler.go b/vendor/github.com/cortexproject/cortex/pkg/ring/lifecycler.go index 73584ea0a2b9..37897b70ba54 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/lifecycler.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/lifecycler.go @@ -17,6 +17,7 @@ import ( "go.uber.org/atomic" "github.com/cortexproject/cortex/pkg/ring/kv" + "github.com/cortexproject/cortex/pkg/util" "github.com/cortexproject/cortex/pkg/util/flagext" "github.com/cortexproject/cortex/pkg/util/log" "github.com/cortexproject/cortex/pkg/util/services" @@ -83,7 +84,7 @@ func (cfg *LifecyclerConfig) RegisterFlagsWithPrefix(prefix string, f *flag.Flag } f.IntVar(&cfg.NumTokens, prefix+"num-tokens", 128, "Number of tokens for each ingester.") - f.DurationVar(&cfg.HeartbeatPeriod, prefix+"heartbeat-period", 5*time.Second, "Period at which to heartbeat to consul.") + f.DurationVar(&cfg.HeartbeatPeriod, prefix+"heartbeat-period", 5*time.Second, "Period at which to heartbeat to consul. 0 = disabled.") f.DurationVar(&cfg.JoinAfter, prefix+"join-after", 0*time.Second, "Period to wait for a claim from another member; will join automatically after this.") f.DurationVar(&cfg.ObservePeriod, prefix+"observe-period", 0*time.Second, "Observe tokens after generating to resolve collisions. Useful when using gossiping ring.") f.DurationVar(&cfg.MinReadyDuration, prefix+"min-ready-duration", 1*time.Minute, "Minimum duration to wait before becoming ready. This is to work around race conditions with ingesters exiting and updating the ring.") @@ -392,8 +393,8 @@ func (i *Lifecycler) loop(ctx context.Context) error { autoJoinAfter := time.After(i.cfg.JoinAfter) var observeChan <-chan time.Time = nil - heartbeatTicker := time.NewTicker(i.cfg.HeartbeatPeriod) - defer heartbeatTicker.Stop() + heartbeatTickerStop, heartbeatTickerChan := util.NewDisableableTicker(i.cfg.HeartbeatPeriod) + defer heartbeatTickerStop() for { select { @@ -442,7 +443,7 @@ func (i *Lifecycler) loop(ctx context.Context) error { observeChan = time.After(i.cfg.ObservePeriod) } - case <-heartbeatTicker.C: + case <-heartbeatTickerChan: consulHeartbeats.WithLabelValues(i.RingName).Inc() if err := i.updateConsul(context.Background()); err != nil { level.Error(log.Logger).Log("msg", "failed to write to the KV store, sleeping", "ring", i.RingName, "err", err) @@ -469,8 +470,8 @@ func (i *Lifecycler) stopping(runningError error) error { return nil } - heartbeatTicker := time.NewTicker(i.cfg.HeartbeatPeriod) - defer heartbeatTicker.Stop() + heartbeatTickerStop, heartbeatTickerChan := util.NewDisableableTicker(i.cfg.HeartbeatPeriod) + defer heartbeatTickerStop() // Mark ourselved as Leaving so no more samples are send to us. err := i.changeState(context.Background(), LEAVING) @@ -489,7 +490,7 @@ func (i *Lifecycler) stopping(runningError error) error { heartbeatLoop: for { select { - case <-heartbeatTicker.C: + case <-heartbeatTickerChan: consulHeartbeats.WithLabelValues(i.RingName).Inc() if err := i.updateConsul(context.Background()); err != nil { level.Error(log.Logger).Log("msg", "failed to write to the KV store, sleeping", "ring", i.RingName, "err", err) diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/model.go b/vendor/github.com/cortexproject/cortex/pkg/ring/model.go index 0e7b6da4d850..3a257c395285 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/model.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/model.go @@ -101,7 +101,7 @@ func (d *Desc) FindIngestersByState(state InstanceState) []InstanceDesc { func (d *Desc) Ready(now time.Time, heartbeatTimeout time.Duration) error { numTokens := 0 for id, ingester := range d.Ingesters { - if now.Sub(time.Unix(ingester.Timestamp, 0)) > heartbeatTimeout { + if !ingester.IsHeartbeatHealthy(heartbeatTimeout, now) { return fmt.Errorf("instance %s past heartbeat timeout", id) } else if ingester.State != ACTIVE { return fmt.Errorf("instance %s in state %v", id, ingester.State) @@ -136,7 +136,16 @@ func (i *InstanceDesc) GetRegisteredAt() time.Time { func (i *InstanceDesc) IsHealthy(op Operation, heartbeatTimeout time.Duration, now time.Time) bool { healthy := op.IsInstanceInStateHealthy(i.State) - return healthy && now.Unix()-i.Timestamp <= heartbeatTimeout.Milliseconds()/1000 + return healthy && i.IsHeartbeatHealthy(heartbeatTimeout, now) +} + +// IsHeartbeatHealthy returns whether the heartbeat timestamp for the ingester is within the +// specified timeout period. A timeout of zero disables the timeout; the heartbeat is ignored. +func (i *InstanceDesc) IsHeartbeatHealthy(heartbeatTimeout time.Duration, now time.Time) bool { + if heartbeatTimeout == 0 { + return true + } + return now.Sub(time.Unix(i.Timestamp, 0)) <= heartbeatTimeout } // Merge merges other ring into this one. Returns sub-ring that represents the change, @@ -374,15 +383,24 @@ func resolveConflicts(normalizedIngesters map[string]InstanceDesc) { } // RemoveTombstones removes LEFT ingesters older than given time limit. If time limit is zero, remove all LEFT ingesters. -func (d *Desc) RemoveTombstones(limit time.Time) { - removed := 0 +func (d *Desc) RemoveTombstones(limit time.Time) (total, removed int) { for n, ing := range d.Ingesters { - if ing.State == LEFT && (limit.IsZero() || time.Unix(ing.Timestamp, 0).Before(limit)) { - // remove it - delete(d.Ingesters, n) - removed++ + if ing.State == LEFT { + if limit.IsZero() || time.Unix(ing.Timestamp, 0).Before(limit) { + // remove it + delete(d.Ingesters, n) + removed++ + } else { + total++ + } } } + return +} + +// Clone returns a deep copy of the ring state. +func (d *Desc) Clone() memberlist.Mergeable { + return proto.Clone(d).(*Desc) } func (d *Desc) getTokensInfo() map[uint32]instanceInfo { diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/ring.go b/vendor/github.com/cortexproject/cortex/pkg/ring/ring.go index 539ec65e75e1..72165ed369d2 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/ring.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/ring.go @@ -71,6 +71,10 @@ type ReadRing interface { // and size (number of instances). ShuffleShard(identifier string, size int) ReadRing + // GetInstanceState returns the current state of an instance or an error if the + // instance does not exist in the ring. + GetInstanceState(instanceID string) (InstanceState, error) + // ShuffleShardWithLookback is like ShuffleShard() but the returned subring includes // all instances that have been part of the identifier's shard since "now - lookbackPeriod". ShuffleShardWithLookback(identifier string, size int, lookbackPeriod time.Duration, now time.Time) ReadRing @@ -143,7 +147,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { cfg.KVStore.RegisterFlagsWithPrefix(prefix, "collectors/", f) - f.DurationVar(&cfg.HeartbeatTimeout, prefix+"ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which ingesters are skipped for reads/writes.") + f.DurationVar(&cfg.HeartbeatTimeout, prefix+"ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which ingesters are skipped for reads/writes. 0 = never (timeout disabled).") f.IntVar(&cfg.ReplicationFactor, prefix+"distributor.replication-factor", 3, "The number of ingesters to write to and read from.") f.BoolVar(&cfg.ZoneAwarenessEnabled, prefix+"distributor.zone-awareness-enabled", false, "True to enable the zone-awareness and replicate ingested samples across different availability zones.") } diff --git a/vendor/github.com/cortexproject/cortex/pkg/ring/util.go b/vendor/github.com/cortexproject/cortex/pkg/ring/util.go index ac5c27388c90..06e053dd2691 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ring/util.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ring/util.go @@ -69,7 +69,7 @@ func GetInstancePort(configPort, listenPort int) int { // WaitInstanceState waits until the input instanceID is registered within the // ring matching the provided state. A timeout should be provided within the context. -func WaitInstanceState(ctx context.Context, r *Ring, instanceID string, state InstanceState) error { +func WaitInstanceState(ctx context.Context, r ReadRing, instanceID string, state InstanceState) error { backoff := util.NewBackoff(ctx, util.BackoffConfig{ MinBackoff: 100 * time.Millisecond, MaxBackoff: time.Second, diff --git a/vendor/github.com/cortexproject/cortex/pkg/ruler/compat.go b/vendor/github.com/cortexproject/cortex/pkg/ruler/compat.go index cc76cfadc2fd..c95cfcd94461 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ruler/compat.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ruler/compat.go @@ -6,7 +6,9 @@ import ( "time" "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/prometheus/notifier" "github.com/prometheus/prometheus/pkg/exemplar" "github.com/prometheus/prometheus/pkg/labels" @@ -14,9 +16,12 @@ import ( "github.com/prometheus/prometheus/promql" "github.com/prometheus/prometheus/rules" "github.com/prometheus/prometheus/storage" + "github.com/weaveworks/common/httpgrpc" "github.com/weaveworks/common/user" "github.com/cortexproject/cortex/pkg/cortexpb" + "github.com/cortexproject/cortex/pkg/querier" + util_log "github.com/cortexproject/cortex/pkg/util/log" ) // Pusher is an ingester server that accepts pushes. @@ -24,7 +29,10 @@ type Pusher interface { Push(context.Context, *cortexpb.WriteRequest) (*cortexpb.WriteResponse, error) } -type pusherAppender struct { +type PusherAppender struct { + failedWrites prometheus.Counter + totalWrites prometheus.Counter + ctx context.Context pusher Pusher labels []labels.Labels @@ -33,7 +41,7 @@ type pusherAppender struct { evaluationDelay time.Duration } -func (a *pusherAppender) Append(_ uint64, l labels.Labels, t int64, v float64) (uint64, error) { +func (a *PusherAppender) Append(_ uint64, l labels.Labels, t int64, v float64) (uint64, error) { a.labels = append(a.labels, l) // Adapt staleness markers for ruler evaluation delay. As the upstream code @@ -41,7 +49,10 @@ func (a *pusherAppender) Append(_ uint64, l labels.Labels, t int64, v float64) ( // This then causes 'out of order' append failures once the series is // becoming available again. // see https://github.com/prometheus/prometheus/blob/6c56a1faaaad07317ff585bda75b99bdba0517ad/rules/manager.go#L647-L660 - if a.evaluationDelay > 0 && value.IsStaleNaN(v) { + // Similar to staleness markers, the rule manager also appends actual time to the ALERTS and ALERTS_FOR_STATE series. + // See: https://github.com/prometheus/prometheus/blob/ae086c73cb4d6db9e8b67d5038d3704fea6aec4a/rules/alerting.go#L414-L417 + metricName := l.Get(labels.MetricName) + if a.evaluationDelay > 0 && (value.IsStaleNaN(v) || metricName == "ALERTS" || metricName == "ALERTS_FOR_STATE") { t -= a.evaluationDelay.Milliseconds() } @@ -52,20 +63,30 @@ func (a *pusherAppender) Append(_ uint64, l labels.Labels, t int64, v float64) ( return 0, nil } -func (a *pusherAppender) AppendExemplar(_ uint64, _ labels.Labels, _ exemplar.Exemplar) (uint64, error) { +func (a *PusherAppender) AppendExemplar(_ uint64, _ labels.Labels, _ exemplar.Exemplar) (uint64, error) { return 0, errors.New("exemplars are unsupported") } -func (a *pusherAppender) Commit() error { +func (a *PusherAppender) Commit() error { + a.totalWrites.Inc() + // Since a.pusher is distributor, client.ReuseSlice will be called in a.pusher.Push. // We shouldn't call client.ReuseSlice here. _, err := a.pusher.Push(user.InjectOrgID(a.ctx, a.userID), cortexpb.ToWriteRequest(a.labels, a.samples, nil, cortexpb.RULE)) + + if err != nil { + // Don't report errors that ended with 4xx HTTP status code (series limits, duplicate samples, out of order, etc.) + if resp, ok := httpgrpc.HTTPResponseFromError(err); !ok || resp.Code/100 != 4 { + a.failedWrites.Inc() + } + } + a.labels = nil a.samples = nil return err } -func (a *pusherAppender) Rollback() error { +func (a *PusherAppender) Rollback() error { a.labels = nil a.samples = nil return nil @@ -76,11 +97,27 @@ type PusherAppendable struct { pusher Pusher userID string rulesLimits RulesLimits + + totalWrites prometheus.Counter + failedWrites prometheus.Counter +} + +func NewPusherAppendable(pusher Pusher, userID string, limits RulesLimits, totalWrites, failedWrites prometheus.Counter) *PusherAppendable { + return &PusherAppendable{ + pusher: pusher, + userID: userID, + rulesLimits: limits, + totalWrites: totalWrites, + failedWrites: failedWrites, + } } // Appender returns a storage.Appender func (t *PusherAppendable) Appender(ctx context.Context) storage.Appender { - return &pusherAppender{ + return &PusherAppender{ + failedWrites: t.failedWrites, + totalWrites: t.totalWrites, + ctx: ctx, pusher: t.pusher, userID: t.userID, @@ -96,9 +133,9 @@ type RulesLimits interface { RulerMaxRulesPerRuleGroup(userID string) int } -// engineQueryFunc returns a new query function using the rules.EngineQueryFunc function +// EngineQueryFunc returns a new query function using the rules.EngineQueryFunc function // and passing an altered timestamp. -func engineQueryFunc(engine *promql.Engine, q storage.Queryable, overrides RulesLimits, userID string) rules.QueryFunc { +func EngineQueryFunc(engine *promql.Engine, q storage.Queryable, overrides RulesLimits, userID string) rules.QueryFunc { return func(ctx context.Context, qs string, t time.Time) (promql.Vector, error) { orig := rules.EngineQueryFunc(engine, q) // Delay the evaluation of all rules by a set interval to give a buffer @@ -108,6 +145,51 @@ func engineQueryFunc(engine *promql.Engine, q storage.Queryable, overrides Rules } } +func MetricsQueryFunc(qf rules.QueryFunc, queries, failedQueries prometheus.Counter) rules.QueryFunc { + return func(ctx context.Context, qs string, t time.Time) (promql.Vector, error) { + queries.Inc() + result, err := qf(ctx, qs, t) + // We rely on TranslateToPromqlApiError to do its job here... it returns nil, if err is nil. + // It returns promql.ErrStorage, if error should be reported back as 500. + // Other errors it returns are either for canceled or timed-out queriers (we're not reporting those as failures), + // or various user-errors (limits, duplicate samples, etc. ... also not failures). + // + // All errors will still be counted towards "evaluation failures" metrics and logged by Prometheus Ruler, + // but we only want internal errors here. + if _, ok := querier.TranslateToPromqlAPIError(err).(promql.ErrStorage); ok { + failedQueries.Inc() + } + return result, err + } +} + +func RecordAndReportRuleQueryMetrics(qf rules.QueryFunc, queryTime prometheus.Counter, logger log.Logger) rules.QueryFunc { + if queryTime == nil { + return qf + } + + return func(ctx context.Context, qs string, t time.Time) (promql.Vector, error) { + // If we've been passed a counter we want to record the wall time spent executing this request. + timer := prometheus.NewTimer(nil) + defer func() { + querySeconds := timer.ObserveDuration().Seconds() + queryTime.Add(querySeconds) + + // Log ruler query stats. + logMessage := []interface{}{ + "msg", "query stats", + "component", "ruler", + "cortex_ruler_query_seconds_total", querySeconds, + "query", qs, + } + level.Info(util_log.WithContext(ctx, logger)).Log(logMessage...) + }() + + result, err := qf(ctx, qs, t) + return result, err + } +} + // This interface mimicks rules.Manager API. Interface is used to simplify tests. type RulesManager interface { // Starts rules manager. Blocks until Stop is called. @@ -126,12 +208,42 @@ type RulesManager interface { // ManagerFactory is a function that creates new RulesManager for given user and notifier.Manager. type ManagerFactory func(ctx context.Context, userID string, notifier *notifier.Manager, logger log.Logger, reg prometheus.Registerer) RulesManager -func DefaultTenantManagerFactory(cfg Config, p Pusher, q storage.Queryable, engine *promql.Engine, overrides RulesLimits) ManagerFactory { +func DefaultTenantManagerFactory(cfg Config, p Pusher, q storage.Queryable, engine *promql.Engine, overrides RulesLimits, reg prometheus.Registerer) ManagerFactory { + totalWrites := promauto.With(reg).NewCounter(prometheus.CounterOpts{ + Name: "cortex_ruler_write_requests_total", + Help: "Number of write requests to ingesters.", + }) + failedWrites := promauto.With(reg).NewCounter(prometheus.CounterOpts{ + Name: "cortex_ruler_write_requests_failed_total", + Help: "Number of failed write requests to ingesters.", + }) + + totalQueries := promauto.With(reg).NewCounter(prometheus.CounterOpts{ + Name: "cortex_ruler_queries_total", + Help: "Number of queries executed by ruler.", + }) + failedQueries := promauto.With(reg).NewCounter(prometheus.CounterOpts{ + Name: "cortex_ruler_queries_failed_total", + Help: "Number of failed queries by ruler.", + }) + var rulerQuerySeconds *prometheus.CounterVec + if cfg.EnableQueryStats { + rulerQuerySeconds = promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ + Name: "cortex_ruler_query_seconds_total", + Help: "Total amount of wall clock time spent processing queries by the ruler.", + }, []string{"user"}) + } + return func(ctx context.Context, userID string, notifier *notifier.Manager, logger log.Logger, reg prometheus.Registerer) RulesManager { + var queryTime prometheus.Counter = nil + if rulerQuerySeconds != nil { + queryTime = rulerQuerySeconds.WithLabelValues(userID) + } + return rules.NewManager(&rules.ManagerOptions{ - Appendable: &PusherAppendable{pusher: p, userID: userID, rulesLimits: overrides}, + Appendable: NewPusherAppendable(p, userID, overrides, totalWrites, failedWrites), Queryable: q, - QueryFunc: engineQueryFunc(engine, q, overrides, userID), + QueryFunc: RecordAndReportRuleQueryMetrics(MetricsQueryFunc(EngineQueryFunc(engine, q, overrides, userID), totalQueries, failedQueries), queryTime, logger), Context: user.InjectOrgID(ctx, userID), ExternalURL: cfg.ExternalURL.URL, NotifyFunc: SendAlerts(notifier, cfg.ExternalURL.URL.String()), diff --git a/vendor/github.com/cortexproject/cortex/pkg/ruler/ruler.go b/vendor/github.com/cortexproject/cortex/pkg/ruler/ruler.go index 25061a8d3538..57b51ed103cd 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ruler/ruler.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ruler/ruler.go @@ -115,6 +115,8 @@ type Config struct { DisabledTenants flagext.StringSliceCSV `yaml:"disabled_tenants"` RingCheckPeriod time.Duration `yaml:"-"` + + EnableQueryStats bool `yaml:"query_stats_enabled"` } // Validate config and returns error on failure @@ -173,6 +175,8 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { f.Var(&cfg.EnabledTenants, "ruler.enabled-tenants", "Comma separated list of tenants whose rules this ruler can evaluate. If specified, only these tenants will be handled by ruler, otherwise this ruler can process rules from all tenants. Subject to sharding.") f.Var(&cfg.DisabledTenants, "ruler.disabled-tenants", "Comma separated list of tenants whose rules this ruler cannot evaluate. If specified, a ruler that would normally pick the specified tenant(s) for processing will ignore them instead. Subject to sharding.") + f.BoolVar(&cfg.EnableQueryStats, "ruler.query-stats-enabled", false, "Report the wall time for ruler queries to complete as a per user metric and as an info level log message.") + cfg.RingCheckPeriod = 5 * time.Second } diff --git a/vendor/github.com/cortexproject/cortex/pkg/ruler/ruler_ring.go b/vendor/github.com/cortexproject/cortex/pkg/ruler/ruler_ring.go index 20d2e900abad..e8577e82898a 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ruler/ruler_ring.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ruler/ruler_ring.go @@ -56,8 +56,8 @@ func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { // Ring flags cfg.KVStore.RegisterFlagsWithPrefix("ruler.ring.", "rulers/", f) - f.DurationVar(&cfg.HeartbeatPeriod, "ruler.ring.heartbeat-period", 5*time.Second, "Period at which to heartbeat to the ring.") - f.DurationVar(&cfg.HeartbeatTimeout, "ruler.ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which rulers are considered unhealthy within the ring.") + f.DurationVar(&cfg.HeartbeatPeriod, "ruler.ring.heartbeat-period", 5*time.Second, "Period at which to heartbeat to the ring. 0 = disabled.") + f.DurationVar(&cfg.HeartbeatTimeout, "ruler.ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which rulers are considered unhealthy within the ring. 0 = never (timeout disabled).") // Instance flags cfg.InstanceInterfaceNames = []string{"eth0", "en0"} diff --git a/vendor/github.com/cortexproject/cortex/pkg/ruler/rulestore/config.go b/vendor/github.com/cortexproject/cortex/pkg/ruler/rulestore/config.go index d44843bab8eb..ef5c855eedea 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/ruler/rulestore/config.go +++ b/vendor/github.com/cortexproject/cortex/pkg/ruler/rulestore/config.go @@ -2,11 +2,13 @@ package rulestore import ( "flag" + "reflect" "github.com/cortexproject/cortex/pkg/configs/client" "github.com/cortexproject/cortex/pkg/ruler/rulestore/configdb" "github.com/cortexproject/cortex/pkg/ruler/rulestore/local" "github.com/cortexproject/cortex/pkg/storage/bucket" + "github.com/cortexproject/cortex/pkg/util/flagext" ) // Config configures a rule store. @@ -25,3 +27,11 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { cfg.Local.RegisterFlagsWithPrefix(prefix, f) cfg.RegisterFlagsWithPrefix(prefix, f) } + +// IsDefaults returns true if the storage options have not been set. +func (cfg *Config) IsDefaults() bool { + defaults := Config{} + flagext.DefaultValues(&defaults) + + return reflect.DeepEqual(*cfg, defaults) +} diff --git a/vendor/github.com/cortexproject/cortex/pkg/storegateway/bucket_store_inmemory_server.go b/vendor/github.com/cortexproject/cortex/pkg/storegateway/bucket_store_inmemory_server.go index 9f4db4665166..ff02afb44a72 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/storegateway/bucket_store_inmemory_server.go +++ b/vendor/github.com/cortexproject/cortex/pkg/storegateway/bucket_store_inmemory_server.go @@ -3,8 +3,10 @@ package storegateway import ( "context" + "github.com/gogo/protobuf/types" "github.com/pkg/errors" "github.com/prometheus/prometheus/storage" + "github.com/thanos-io/thanos/pkg/store/hintspb" "github.com/thanos-io/thanos/pkg/store/storepb" ) @@ -19,6 +21,7 @@ type bucketStoreSeriesServer struct { SeriesSet []*storepb.Series Warnings storage.Warnings + Hints hintspb.SeriesResponseHints } func newBucketStoreSeriesServer(ctx context.Context) *bucketStoreSeriesServer { @@ -30,6 +33,13 @@ func (s *bucketStoreSeriesServer) Send(r *storepb.SeriesResponse) error { s.Warnings = append(s.Warnings, errors.New(r.GetWarning())) } + if rawHints := r.GetHints(); rawHints != nil { + // We expect only 1 hints entry so we just keep 1. + if err := types.UnmarshalAny(rawHints, &s.Hints); err != nil { + return errors.Wrap(err, "failed to unmarshal series hints") + } + } + if recvSeries := r.GetSeries(); recvSeries != nil { // Thanos uses a pool for the chunks and may use other pools in the future. // Given we need to retain the reference after the pooled slices are recycled, diff --git a/vendor/github.com/cortexproject/cortex/pkg/storegateway/gateway.go b/vendor/github.com/cortexproject/cortex/pkg/storegateway/gateway.go index 00a7a093fea7..a9e87bd78dd1 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/storegateway/gateway.go +++ b/vendor/github.com/cortexproject/cortex/pkg/storegateway/gateway.go @@ -231,6 +231,22 @@ func (g *StoreGateway) starting(ctx context.Context) (err error) { return err } level.Info(g.logger).Log("msg", "store-gateway is JOINING in the ring") + + // In the event of a cluster cold start or scale up of 2+ store-gateway instances at the same + // time, we may end up in a situation where each new store-gateway instance starts at a slightly + // different time and thus each one starts with a different state of the ring. It's better + // to just wait the ring stability for a short time. + if g.gatewayCfg.ShardingRing.WaitStabilityMinDuration > 0 { + minWaiting := g.gatewayCfg.ShardingRing.WaitStabilityMinDuration + maxWaiting := g.gatewayCfg.ShardingRing.WaitStabilityMaxDuration + + level.Info(g.logger).Log("msg", "waiting until store-gateway ring topology is stable", "min_waiting", minWaiting.String(), "max_waiting", maxWaiting.String()) + if err := ring.WaitRingStability(ctx, g.ring, BlocksOwnerSync, minWaiting, maxWaiting); err != nil { + level.Warn(g.logger).Log("msg", "store-gateway ring topology is not stable after the max waiting time, proceeding anyway") + } else { + level.Info(g.logger).Log("msg", "store-gateway ring topology is stable") + } + } } // At this point, if sharding is enabled, the instance is registered with some tokens @@ -271,7 +287,7 @@ func (g *StoreGateway) running(ctx context.Context) error { defer syncTicker.Stop() if g.gatewayCfg.ShardingEnabled { - ringLastState, _ = g.ring.GetAllHealthy(BlocksSync) // nolint:errcheck + ringLastState, _ = g.ring.GetAllHealthy(BlocksOwnerSync) // nolint:errcheck ringTicker := time.NewTicker(util.DurationWithJitter(g.gatewayCfg.ShardingRing.RingCheckPeriod, 0.2)) defer ringTicker.Stop() ringTickerChan = ringTicker.C @@ -284,7 +300,7 @@ func (g *StoreGateway) running(ctx context.Context) error { case <-ringTickerChan: // We ignore the error because in case of error it will return an empty // replication set which we use to compare with the previous state. - currRingState, _ := g.ring.GetAllHealthy(BlocksSync) // nolint:errcheck + currRingState, _ := g.ring.GetAllHealthy(BlocksOwnerSync) // nolint:errcheck if ring.HasReplicationSetChanged(ringLastState, currRingState) { ringLastState = currRingState diff --git a/vendor/github.com/cortexproject/cortex/pkg/storegateway/gateway_ring.go b/vendor/github.com/cortexproject/cortex/pkg/storegateway/gateway_ring.go index 652a98020db2..c868c2b789d2 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/storegateway/gateway_ring.go +++ b/vendor/github.com/cortexproject/cortex/pkg/storegateway/gateway_ring.go @@ -31,17 +31,27 @@ const ( ) var ( - // BlocksSync is the operation run by the store-gateway to sync blocks. - BlocksSync = ring.NewOp([]ring.InstanceState{ring.JOINING, ring.ACTIVE, ring.LEAVING}, func(s ring.InstanceState) bool { - // If the instance is JOINING or LEAVING we should extend the replica set: - // - JOINING: the previous replica set should be kept while an instance is JOINING - // - LEAVING: the instance is going to be decommissioned soon so we need to include - // another replica in the set - return s == ring.JOINING || s == ring.LEAVING + // BlocksOwnerSync is the operation used to check the authoritative owners of a block + // (replicas included). + BlocksOwnerSync = ring.NewOp([]ring.InstanceState{ring.JOINING, ring.ACTIVE, ring.LEAVING}, func(s ring.InstanceState) bool { + // Extend the replication set only when an instance is LEAVING so that + // their blocks will be loaded sooner on the next authoritative owner(s). + return s == ring.LEAVING }) + // BlocksOwnerRead is the operation used to check the authoritative owners of a block + // (replicas included) that are available for queries (a store-gateway is available for + // queries only when ACTIVE). + BlocksOwnerRead = ring.NewOp([]ring.InstanceState{ring.ACTIVE}, nil) + // BlocksRead is the operation run by the querier to query blocks via the store-gateway. - BlocksRead = ring.NewOp([]ring.InstanceState{ring.ACTIVE}, nil) + BlocksRead = ring.NewOp([]ring.InstanceState{ring.ACTIVE}, func(s ring.InstanceState) bool { + // Blocks can only be queried from ACTIVE instances. However, if the block belongs to + // a non-active instance, then we should extend the replication set and try to query it + // from the next ACTIVE instance in the ring (which is expected to have it because a + // store-gateway keeps their previously owned blocks until new owners are ACTIVE). + return s != ring.ACTIVE + }) ) // RingConfig masks the ring lifecycler config which contains @@ -56,6 +66,10 @@ type RingConfig struct { TokensFilePath string `yaml:"tokens_file_path"` ZoneAwarenessEnabled bool `yaml:"zone_awareness_enabled"` + // Wait ring stability. + WaitStabilityMinDuration time.Duration `yaml:"wait_stability_min_duration"` + WaitStabilityMaxDuration time.Duration `yaml:"wait_stability_max_duration"` + // Instance details InstanceID string `yaml:"instance_id" doc:"hidden"` InstanceInterfaceNames []string `yaml:"instance_interface_names"` @@ -80,12 +94,16 @@ func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { // Ring flags cfg.KVStore.RegisterFlagsWithPrefix(ringFlagsPrefix, "collectors/", f) - f.DurationVar(&cfg.HeartbeatPeriod, ringFlagsPrefix+"heartbeat-period", 15*time.Second, "Period at which to heartbeat to the ring.") - f.DurationVar(&cfg.HeartbeatTimeout, ringFlagsPrefix+"heartbeat-timeout", time.Minute, "The heartbeat timeout after which store gateways are considered unhealthy within the ring."+sharedOptionWithQuerier) + f.DurationVar(&cfg.HeartbeatPeriod, ringFlagsPrefix+"heartbeat-period", 15*time.Second, "Period at which to heartbeat to the ring. 0 = disabled.") + f.DurationVar(&cfg.HeartbeatTimeout, ringFlagsPrefix+"heartbeat-timeout", time.Minute, "The heartbeat timeout after which store gateways are considered unhealthy within the ring. 0 = never (timeout disabled)."+sharedOptionWithQuerier) f.IntVar(&cfg.ReplicationFactor, ringFlagsPrefix+"replication-factor", 3, "The replication factor to use when sharding blocks."+sharedOptionWithQuerier) f.StringVar(&cfg.TokensFilePath, ringFlagsPrefix+"tokens-file-path", "", "File path where tokens are stored. If empty, tokens are not stored at shutdown and restored at startup.") f.BoolVar(&cfg.ZoneAwarenessEnabled, ringFlagsPrefix+"zone-awareness-enabled", false, "True to enable zone-awareness and replicate blocks across different availability zones.") + // Wait stability flags. + f.DurationVar(&cfg.WaitStabilityMinDuration, ringFlagsPrefix+"wait-stability-min-duration", time.Minute, "Minimum time to wait for ring stability at startup. 0 to disable.") + f.DurationVar(&cfg.WaitStabilityMaxDuration, ringFlagsPrefix+"wait-stability-max-duration", 5*time.Minute, "Maximum time to wait for ring stability at startup. If the store-gateway ring keeps changing after this period of time, the store-gateway will start anyway.") + // Instance flags cfg.InstanceInterfaceNames = []string{"eth0", "en0"} f.Var((*flagext.StringSlice)(&cfg.InstanceInterfaceNames), ringFlagsPrefix+"instance-interface-names", "Name of network interface to read address from.") diff --git a/vendor/github.com/cortexproject/cortex/pkg/storegateway/sharding_strategy.go b/vendor/github.com/cortexproject/cortex/pkg/storegateway/sharding_strategy.go index ced8c5701e14..6982e830d03b 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/storegateway/sharding_strategy.go +++ b/vendor/github.com/cortexproject/cortex/pkg/storegateway/sharding_strategy.go @@ -24,8 +24,10 @@ type ShardingStrategy interface { // that should be synced by the store-gateway. FilterUsers(ctx context.Context, userIDs []string) []string - // FilterBlocks that should be loaded by the store-gateway. - FilterBlocks(ctx context.Context, userID string, metas map[ulid.ULID]*metadata.Meta, synced *extprom.TxGaugeVec) error + // FilterBlocks filters metas in-place keeping only blocks that should be loaded by the store-gateway. + // The provided loaded map contains blocks which have been previously returned by this function and + // are now loaded or loading in the store-gateway. + FilterBlocks(ctx context.Context, userID string, metas map[ulid.ULID]*metadata.Meta, loaded map[ulid.ULID]struct{}, synced *extprom.TxGaugeVec) error } // ShardingLimits is the interface that should be implemented by the limits provider, @@ -45,7 +47,7 @@ func (s *NoShardingStrategy) FilterUsers(_ context.Context, userIDs []string) [] return userIDs } -func (s *NoShardingStrategy) FilterBlocks(_ context.Context, _ string, _ map[ulid.ULID]*metadata.Meta, _ *extprom.TxGaugeVec) error { +func (s *NoShardingStrategy) FilterBlocks(_ context.Context, _ string, _ map[ulid.ULID]*metadata.Meta, _ map[ulid.ULID]struct{}, _ *extprom.TxGaugeVec) error { return nil } @@ -72,8 +74,8 @@ func (s *DefaultShardingStrategy) FilterUsers(_ context.Context, userIDs []strin } // FilterBlocks implements ShardingStrategy. -func (s *DefaultShardingStrategy) FilterBlocks(_ context.Context, _ string, metas map[ulid.ULID]*metadata.Meta, synced *extprom.TxGaugeVec) error { - filterBlocksByRingSharding(s.r, s.instanceAddr, metas, synced, s.logger) +func (s *DefaultShardingStrategy) FilterBlocks(_ context.Context, _ string, metas map[ulid.ULID]*metadata.Meta, loaded map[ulid.ULID]struct{}, synced *extprom.TxGaugeVec) error { + filterBlocksByRingSharding(s.r, s.instanceAddr, metas, loaded, synced, s.logger) return nil } @@ -115,30 +117,57 @@ func (s *ShuffleShardingStrategy) FilterUsers(_ context.Context, userIDs []strin } // FilterBlocks implements ShardingStrategy. -func (s *ShuffleShardingStrategy) FilterBlocks(_ context.Context, userID string, metas map[ulid.ULID]*metadata.Meta, synced *extprom.TxGaugeVec) error { +func (s *ShuffleShardingStrategy) FilterBlocks(_ context.Context, userID string, metas map[ulid.ULID]*metadata.Meta, loaded map[ulid.ULID]struct{}, synced *extprom.TxGaugeVec) error { subRing := GetShuffleShardingSubring(s.r, userID, s.limits) - filterBlocksByRingSharding(subRing, s.instanceAddr, metas, synced, s.logger) + filterBlocksByRingSharding(subRing, s.instanceAddr, metas, loaded, synced, s.logger) return nil } -func filterBlocksByRingSharding(r ring.ReadRing, instanceAddr string, metas map[ulid.ULID]*metadata.Meta, synced *extprom.TxGaugeVec, logger log.Logger) { +func filterBlocksByRingSharding(r ring.ReadRing, instanceAddr string, metas map[ulid.ULID]*metadata.Meta, loaded map[ulid.ULID]struct{}, synced *extprom.TxGaugeVec, logger log.Logger) { bufDescs, bufHosts, bufZones := ring.MakeBuffersForGet() for blockID := range metas { key := cortex_tsdb.HashBlockID(blockID) - set, err := r.Get(key, BlocksSync, bufDescs, bufHosts, bufZones) - - // If there are no healthy instances in the replication set or - // the replication set for this block doesn't include this instance - // then we filter it out. - if err != nil || !set.Includes(instanceAddr) { - if err != nil { - level.Warn(logger).Log("msg", "excluded block because failed to get replication set", "block", blockID.String(), "err", err) + + // Check if the block is owned by the store-gateway + set, err := r.Get(key, BlocksOwnerSync, bufDescs, bufHosts, bufZones) + + // If an error occurs while checking the ring, we keep the previously loaded blocks. + if err != nil { + if _, ok := loaded[blockID]; ok { + level.Warn(logger).Log("msg", "failed to check block owner but block is kept because was previously loaded", "block", blockID.String(), "err", err) + } else { + level.Warn(logger).Log("msg", "failed to check block owner and block has been excluded because was not previously loaded", "block", blockID.String(), "err", err) + + // Skip the block. + synced.WithLabelValues(shardExcludedMeta).Inc() + delete(metas, blockID) } - synced.WithLabelValues(shardExcludedMeta).Inc() - delete(metas, blockID) + continue + } + + // Keep the block if it is owned by the store-gateway. + if set.Includes(instanceAddr) { + continue + } + + // The block is not owned by the store-gateway. However, if it's currently loaded + // we can safely unload it only once at least 1 authoritative owner is available + // for queries. + if _, ok := loaded[blockID]; ok { + // The ring Get() returns an error if there's no available instance. + if _, err := r.Get(key, BlocksOwnerRead, bufDescs, bufHosts, bufZones); err != nil { + // Keep the block. + continue + } } + + // The block is not owned by the store-gateway and there's at least 1 available + // authoritative owner available for queries, so we can filter it out (and unload + // it if it was loaded). + synced.WithLabelValues(shardExcludedMeta).Inc() + delete(metas, blockID) } } @@ -159,18 +188,33 @@ func GetShuffleShardingSubring(ring *ring.Ring, userID string, limits ShardingLi type shardingMetadataFilterAdapter struct { userID string strategy ShardingStrategy + + // Keep track of the last blocks returned by the Filter() function. + lastBlocks map[ulid.ULID]struct{} } func NewShardingMetadataFilterAdapter(userID string, strategy ShardingStrategy) block.MetadataFilter { return &shardingMetadataFilterAdapter{ - userID: userID, - strategy: strategy, + userID: userID, + strategy: strategy, + lastBlocks: map[ulid.ULID]struct{}{}, } } // Filter implements block.MetadataFilter. +// This function is NOT safe for use by multiple goroutines concurrently. func (a *shardingMetadataFilterAdapter) Filter(ctx context.Context, metas map[ulid.ULID]*metadata.Meta, synced *extprom.TxGaugeVec) error { - return a.strategy.FilterBlocks(ctx, a.userID, metas, synced) + if err := a.strategy.FilterBlocks(ctx, a.userID, metas, a.lastBlocks, synced); err != nil { + return err + } + + // Keep track of the last filtered blocks. + a.lastBlocks = make(map[ulid.ULID]struct{}, len(metas)) + for blockID := range metas { + a.lastBlocks[blockID] = struct{}{} + } + + return nil } type shardingBucketReaderAdapter struct { diff --git a/vendor/github.com/cortexproject/cortex/pkg/util/limiter/query_limiter.go b/vendor/github.com/cortexproject/cortex/pkg/util/limiter/query_limiter.go index 9560c6c12e65..b5c33c62efb9 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/util/limiter/query_limiter.go +++ b/vendor/github.com/cortexproject/cortex/pkg/util/limiter/query_limiter.go @@ -6,34 +6,43 @@ import ( "sync" "github.com/prometheus/common/model" + "go.uber.org/atomic" "github.com/cortexproject/cortex/pkg/cortexpb" "github.com/cortexproject/cortex/pkg/ingester/client" - "github.com/cortexproject/cortex/pkg/util/validation" ) type queryLimiterCtxKey struct{} var ( - ctxKey = &queryLimiterCtxKey{} - errMaxSeriesHit = "The query hit the max number of series limit (limit: %d)" + ctxKey = &queryLimiterCtxKey{} + ErrMaxSeriesHit = "the query hit the max number of series limit (limit: %d series)" + ErrMaxChunkBytesHit = "the query hit the aggregated chunks size limit (limit: %d bytes)" + ErrMaxChunksPerQueryLimit = "the query hit the max number of chunks limit (limit: %d chunks)" ) type QueryLimiter struct { uniqueSeriesMx sync.Mutex uniqueSeries map[model.Fingerprint]struct{} - maxSeriesPerQuery int + chunkBytesCount atomic.Int64 + chunkCount atomic.Int64 + + maxSeriesPerQuery int + maxChunkBytesPerQuery int + maxChunksPerQuery int } // NewQueryLimiter makes a new per-query limiter. Each query limiter // is configured using the `maxSeriesPerQuery` limit. -func NewQueryLimiter(maxSeriesPerQuery int) *QueryLimiter { +func NewQueryLimiter(maxSeriesPerQuery, maxChunkBytesPerQuery int, maxChunksPerQuery int) *QueryLimiter { return &QueryLimiter{ uniqueSeriesMx: sync.Mutex{}, uniqueSeries: map[model.Fingerprint]struct{}{}, - maxSeriesPerQuery: maxSeriesPerQuery, + maxSeriesPerQuery: maxSeriesPerQuery, + maxChunkBytesPerQuery: maxChunkBytesPerQuery, + maxChunksPerQuery: maxChunksPerQuery, } } @@ -47,7 +56,7 @@ func QueryLimiterFromContextWithFallback(ctx context.Context) *QueryLimiter { ql, ok := ctx.Value(ctxKey).(*QueryLimiter) if !ok { // If there's no limiter return a new unlimited limiter as a fallback - ql = NewQueryLimiter(0) + ql = NewQueryLimiter(0, 0, 0) } return ql } @@ -66,7 +75,7 @@ func (ql *QueryLimiter) AddSeries(seriesLabels []cortexpb.LabelAdapter) error { ql.uniqueSeries[fingerprint] = struct{}{} if len(ql.uniqueSeries) > ql.maxSeriesPerQuery { // Format error with max limit - return validation.LimitError(fmt.Sprintf(errMaxSeriesHit, ql.maxSeriesPerQuery)) + return fmt.Errorf(ErrMaxSeriesHit, ql.maxSeriesPerQuery) } return nil } @@ -77,3 +86,25 @@ func (ql *QueryLimiter) uniqueSeriesCount() int { defer ql.uniqueSeriesMx.Unlock() return len(ql.uniqueSeries) } + +// AddChunkBytes adds the input chunk size in bytes and returns an error if the limit is reached. +func (ql *QueryLimiter) AddChunkBytes(chunkSizeInBytes int) error { + if ql.maxChunkBytesPerQuery == 0 { + return nil + } + if ql.chunkBytesCount.Add(int64(chunkSizeInBytes)) > int64(ql.maxChunkBytesPerQuery) { + return fmt.Errorf(ErrMaxChunkBytesHit, ql.maxChunkBytesPerQuery) + } + return nil +} + +func (ql *QueryLimiter) AddChunks(count int) error { + if ql.maxChunksPerQuery == 0 { + return nil + } + + if ql.chunkCount.Add(int64(count)) > int64(ql.maxChunksPerQuery) { + return fmt.Errorf(fmt.Sprintf(ErrMaxChunksPerQueryLimit, ql.maxChunksPerQuery)) + } + return nil +} diff --git a/vendor/github.com/cortexproject/cortex/pkg/util/net.go b/vendor/github.com/cortexproject/cortex/pkg/util/net.go index f4cd184870fc..354576ebf18c 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/util/net.go +++ b/vendor/github.com/cortexproject/cortex/pkg/util/net.go @@ -3,21 +3,22 @@ package util import ( "fmt" "net" + "strings" "github.com/go-kit/kit/log/level" util_log "github.com/cortexproject/cortex/pkg/util/log" ) -// GetFirstAddressOf returns the first IPv4 address of the supplied interface names. +// GetFirstAddressOf returns the first IPv4 address of the supplied interface names, omitting any 169.254.x.x automatic private IPs if possible. func GetFirstAddressOf(names []string) (string, error) { + var ipAddr string for _, name := range names { inf, err := net.InterfaceByName(name) if err != nil { level.Warn(util_log.Logger).Log("msg", "error getting interface", "inf", name, "err", err) continue } - addrs, err := inf.Addrs() if err != nil { level.Warn(util_log.Logger).Log("msg", "error getting addresses for interface", "inf", name, "err", err) @@ -27,16 +28,35 @@ func GetFirstAddressOf(names []string) (string, error) { level.Warn(util_log.Logger).Log("msg", "no addresses found for interface", "inf", name, "err", err) continue } + if ip := filterIPs(addrs); ip != "" { + ipAddr = ip + } + if strings.HasPrefix(ipAddr, `169.254.`) || ipAddr == "" { + continue + } + return ipAddr, nil + } + if ipAddr == "" { + return "", fmt.Errorf("No address found for %s", names) + } + if strings.HasPrefix(ipAddr, `169.254.`) { + level.Warn(util_log.Logger).Log("msg", "using automatic private ip", "address", ipAddr) + } + return ipAddr, nil +} - for _, addr := range addrs { - switch v := addr.(type) { - case *net.IPNet: - if ip := v.IP.To4(); ip != nil { - return v.IP.String(), nil +// filterIPs attempts to return the first non automatic private IP (APIPA / 169.254.x.x) if possible, only returning APIPA if available and no other valid IP is found. +func filterIPs(addrs []net.Addr) string { + var ipAddr string + for _, addr := range addrs { + if v, ok := addr.(*net.IPNet); ok { + if ip := v.IP.To4(); ip != nil { + ipAddr = v.IP.String() + if !strings.HasPrefix(ipAddr, `169.254.`) { + return ipAddr } } } } - - return "", fmt.Errorf("No address found for %s", names) + return ipAddr } diff --git a/vendor/github.com/cortexproject/cortex/pkg/util/time.go b/vendor/github.com/cortexproject/cortex/pkg/util/time.go index 58f951a8b3df..8816b1d7d2ee 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/util/time.go +++ b/vendor/github.com/cortexproject/cortex/pkg/util/time.go @@ -73,3 +73,14 @@ func DurationWithPositiveJitter(input time.Duration, variancePerc float64) time. return input + time.Duration(jitter) } + +// NewDisableableTicker essentially wraps NewTicker but allows the ticker to be disabled by passing +// zero duration as the interval. Returns a function for stopping the ticker, and the ticker channel. +func NewDisableableTicker(interval time.Duration) (func(), <-chan time.Time) { + if interval == 0 { + return func() {}, nil + } + + tick := time.NewTicker(interval) + return func() { tick.Stop() }, tick.C +} diff --git a/vendor/github.com/cortexproject/cortex/pkg/util/validation/limits.go b/vendor/github.com/cortexproject/cortex/pkg/util/validation/limits.go index 4e139e676ac3..506e6f6fffa1 100644 --- a/vendor/github.com/cortexproject/cortex/pkg/util/validation/limits.go +++ b/vendor/github.com/cortexproject/cortex/pkg/util/validation/limits.go @@ -1,6 +1,7 @@ package validation import ( + "bytes" "encoding/json" "errors" "flag" @@ -15,9 +16,7 @@ import ( "github.com/cortexproject/cortex/pkg/util/flagext" ) -var ( - errMaxGlobalSeriesPerUserValidation = errors.New("The ingester.max-global-series-per-user limit is unsupported if distributor.shard-by-all-labels is disabled") -) +var errMaxGlobalSeriesPerUserValidation = errors.New("The ingester.max-global-series-per-user limit is unsupported if distributor.shard-by-all-labels is disabled") // Supported values for enum limits const ( @@ -72,15 +71,16 @@ type Limits struct { MaxGlobalMetadataPerMetric int `yaml:"max_global_metadata_per_metric" json:"max_global_metadata_per_metric"` // Querier enforced limits. - MaxChunksPerQueryFromStore int `yaml:"max_chunks_per_query" json:"max_chunks_per_query"` // TODO Remove in Cortex 1.12. - MaxChunksPerQuery int `yaml:"max_fetched_chunks_per_query" json:"max_fetched_chunks_per_query"` - MaxFetchedSeriesPerQuery int `yaml:"max_fetched_series_per_query" json:"max_fetched_series_per_query"` - MaxQueryLookback model.Duration `yaml:"max_query_lookback" json:"max_query_lookback"` - MaxQueryLength model.Duration `yaml:"max_query_length" json:"max_query_length"` - MaxQueryParallelism int `yaml:"max_query_parallelism" json:"max_query_parallelism"` - CardinalityLimit int `yaml:"cardinality_limit" json:"cardinality_limit"` - MaxCacheFreshness model.Duration `yaml:"max_cache_freshness" json:"max_cache_freshness"` - MaxQueriersPerTenant int `yaml:"max_queriers_per_tenant" json:"max_queriers_per_tenant"` + MaxChunksPerQueryFromStore int `yaml:"max_chunks_per_query" json:"max_chunks_per_query"` // TODO Remove in Cortex 1.12. + MaxChunksPerQuery int `yaml:"max_fetched_chunks_per_query" json:"max_fetched_chunks_per_query"` + MaxFetchedSeriesPerQuery int `yaml:"max_fetched_series_per_query" json:"max_fetched_series_per_query"` + MaxFetchedChunkBytesPerQuery int `yaml:"max_fetched_chunk_bytes_per_query" json:"max_fetched_chunk_bytes_per_query"` + MaxQueryLookback model.Duration `yaml:"max_query_lookback" json:"max_query_lookback"` + MaxQueryLength model.Duration `yaml:"max_query_length" json:"max_query_length"` + MaxQueryParallelism int `yaml:"max_query_parallelism" json:"max_query_parallelism"` + CardinalityLimit int `yaml:"cardinality_limit" json:"cardinality_limit"` + MaxCacheFreshness model.Duration `yaml:"max_cache_freshness" json:"max_cache_freshness"` + MaxQueriersPerTenant int `yaml:"max_queriers_per_tenant" json:"max_queriers_per_tenant"` // Ruler defaults and limits. RulerEvaluationDelay model.Duration `yaml:"ruler_evaluation_delay_duration" json:"ruler_evaluation_delay_duration"` @@ -107,9 +107,12 @@ type Limits struct { NotificationRateLimit float64 `yaml:"alertmanager_notification_rate_limit" json:"alertmanager_notification_rate_limit"` NotificationRateLimitPerIntegration NotificationRateLimitMap `yaml:"alertmanager_notification_rate_limit_per_integration" json:"alertmanager_notification_rate_limit_per_integration"` - AlertmanagerMaxConfigSizeBytes int `yaml:"alertmanager_max_config_size_bytes" json:"alertmanager_max_config_size_bytes"` - AlertmanagerMaxTemplatesCount int `yaml:"alertmanager_max_templates_count" json:"alertmanager_max_templates_count"` - AlertmanagerMaxTemplateSizeBytes int `yaml:"alertmanager_max_template_size_bytes" json:"alertmanager_max_template_size_bytes"` + AlertmanagerMaxConfigSizeBytes int `yaml:"alertmanager_max_config_size_bytes" json:"alertmanager_max_config_size_bytes"` + AlertmanagerMaxTemplatesCount int `yaml:"alertmanager_max_templates_count" json:"alertmanager_max_templates_count"` + AlertmanagerMaxTemplateSizeBytes int `yaml:"alertmanager_max_template_size_bytes" json:"alertmanager_max_template_size_bytes"` + AlertmanagerMaxDispatcherAggregationGroups int `yaml:"alertmanager_max_dispatcher_aggregation_groups" json:"alertmanager_max_dispatcher_aggregation_groups"` + AlertmanagerMaxAlertsCount int `yaml:"alertmanager_max_alerts_count" json:"alertmanager_max_alerts_count"` + AlertmanagerMaxAlertsSizeBytes int `yaml:"alertmanager_max_alerts_size_bytes" json:"alertmanager_max_alerts_size_bytes"` } // RegisterFlags adds the flags required to config this to the given FlagSet @@ -139,8 +142,8 @@ func (l *Limits) RegisterFlags(f *flag.FlagSet) { f.IntVar(&l.MaxSamplesPerQuery, "ingester.max-samples-per-query", 1000000, "The maximum number of samples that a query can return. This limit only applies when running the Cortex chunks storage with -querier.ingester-streaming=false.") f.IntVar(&l.MaxLocalSeriesPerUser, "ingester.max-series-per-user", 5000000, "The maximum number of active series per user, per ingester. 0 to disable.") f.IntVar(&l.MaxLocalSeriesPerMetric, "ingester.max-series-per-metric", 50000, "The maximum number of active series per metric name, per ingester. 0 to disable.") - f.IntVar(&l.MaxGlobalSeriesPerUser, "ingester.max-global-series-per-user", 0, "The maximum number of active series per user, across the cluster. 0 to disable. Supported only if -distributor.shard-by-all-labels is true.") - f.IntVar(&l.MaxGlobalSeriesPerMetric, "ingester.max-global-series-per-metric", 0, "The maximum number of active series per metric name, across the cluster. 0 to disable.") + f.IntVar(&l.MaxGlobalSeriesPerUser, "ingester.max-global-series-per-user", 0, "The maximum number of active series per user, across the cluster before replication. 0 to disable. Supported only if -distributor.shard-by-all-labels is true.") + f.IntVar(&l.MaxGlobalSeriesPerMetric, "ingester.max-global-series-per-metric", 0, "The maximum number of active series per metric name, across the cluster before replication. 0 to disable.") f.IntVar(&l.MinChunkLength, "ingester.min-chunk-length", 0, "Minimum number of samples in an idle chunk to flush it to the store. Use with care, if chunks are less than this size they will be discarded. This option is ignored when running the Cortex blocks storage. 0 to disable.") f.IntVar(&l.MaxLocalMetricsWithMetadataPerUser, "ingester.max-metadata-per-user", 8000, "The maximum number of active metrics with metadata per user, per ingester. 0 to disable.") @@ -148,8 +151,9 @@ func (l *Limits) RegisterFlags(f *flag.FlagSet) { f.IntVar(&l.MaxGlobalMetricsWithMetadataPerUser, "ingester.max-global-metadata-per-user", 0, "The maximum number of active metrics with metadata per user, across the cluster. 0 to disable. Supported only if -distributor.shard-by-all-labels is true.") f.IntVar(&l.MaxGlobalMetadataPerMetric, "ingester.max-global-metadata-per-metric", 0, "The maximum number of metadata per metric, across the cluster. 0 to disable.") f.IntVar(&l.MaxChunksPerQueryFromStore, "store.query-chunk-limit", 2e6, "Deprecated. Use -querier.max-fetched-chunks-per-query CLI flag and its respective YAML config option instead. Maximum number of chunks that can be fetched in a single query. This limit is enforced when fetching chunks from the long-term storage only. When running the Cortex chunks storage, this limit is enforced in the querier and ruler, while when running the Cortex blocks storage this limit is enforced in the querier, ruler and store-gateway. 0 to disable.") - f.IntVar(&l.MaxChunksPerQuery, "querier.max-fetched-chunks-per-query", 0, "Maximum number of chunks that can be fetched in a single query from ingesters and long-term storage: the total number of actual fetched chunks could be 2x the limit, being independently applied when querying ingesters and long-term storage. This limit is enforced in the ingester (if chunks streaming is enabled), querier, ruler and store-gateway. Takes precedence over the deprecated -store.query-chunk-limit. 0 to disable.") + f.IntVar(&l.MaxChunksPerQuery, "querier.max-fetched-chunks-per-query", 0, "Maximum number of chunks that can be fetched in a single query from ingesters and long-term storage. This limit is enforced in the querier, ruler and store-gateway. Takes precedence over the deprecated -store.query-chunk-limit. 0 to disable.") f.IntVar(&l.MaxFetchedSeriesPerQuery, "querier.max-fetched-series-per-query", 0, "The maximum number of unique series for which a query can fetch samples from each ingesters and blocks storage. This limit is enforced in the querier only when running Cortex with blocks storage. 0 to disable") + f.IntVar(&l.MaxFetchedChunkBytesPerQuery, "querier.max-fetched-chunk-bytes-per-query", 0, "The maximum size of all chunks in bytes that a query can fetch from each ingester and storage. This limit is enforced in the querier and ruler only when running Cortex with blocks storage. 0 to disable.") f.Var(&l.MaxQueryLength, "store.max-query-length", "Limit the query time range (end - start time). This limit is enforced in the query-frontend (on the received query), in the querier (on the query possibly split by the query-frontend) and in the chunks storage. 0 to disable.") f.Var(&l.MaxQueryLookback, "querier.max-query-lookback", "Limit how long back data (series and metadata) can be queried, up until duration ago. This limit is enforced in the query-frontend, querier and ruler. If the requested time range is outside the allowed range, the request will not fail but will be manipulated to only query data within the allowed time range. 0 to disable.") f.IntVar(&l.MaxQueryParallelism, "querier.max-query-parallelism", 14, "Maximum number of split queries will be scheduled in parallel by the frontend.") @@ -181,6 +185,9 @@ func (l *Limits) RegisterFlags(f *flag.FlagSet) { f.IntVar(&l.AlertmanagerMaxConfigSizeBytes, "alertmanager.max-config-size-bytes", 0, "Maximum size of configuration file for Alertmanager that tenant can upload via Alertmanager API. 0 = no limit.") f.IntVar(&l.AlertmanagerMaxTemplatesCount, "alertmanager.max-templates-count", 0, "Maximum number of templates in tenant's Alertmanager configuration uploaded via Alertmanager API. 0 = no limit.") f.IntVar(&l.AlertmanagerMaxTemplateSizeBytes, "alertmanager.max-template-size-bytes", 0, "Maximum size of single template in tenant's Alertmanager configuration uploaded via Alertmanager API. 0 = no limit.") + f.IntVar(&l.AlertmanagerMaxDispatcherAggregationGroups, "alertmanager.max-dispatcher-aggregation-groups", 0, "Maximum number of aggregation groups in Alertmanager's dispatcher that a tenant can have. Each active aggregation group uses single goroutine. When the limit is reached, dispatcher will not dispatch alerts that belong to additional aggregation groups, but existing groups will keep working properly. 0 = no limit.") + f.IntVar(&l.AlertmanagerMaxAlertsCount, "alertmanager.max-alerts-count", 0, "Maximum number of alerts that a single user can have. Inserting more alerts will fail with a log message and metric increment. 0 = no limit.") + f.IntVar(&l.AlertmanagerMaxAlertsSizeBytes, "alertmanager.max-alerts-size-bytes", 0, "Maximum total size of alerts that a single user can have, alert size is the sum of the bytes of its labels, annotations and generatorURL. Inserting more alerts will fail with a log message and metric increment. 0 = no limit.") } // Validate the limits config and returns an error if the validation @@ -223,7 +230,10 @@ func (l *Limits) UnmarshalJSON(data []byte) error { } type plain Limits - return json.Unmarshal(data, (*plain)(l)) + dec := json.NewDecoder(bytes.NewReader(data)) + dec.DisallowUnknownFields() + + return dec.Decode((*plain)(l)) } func (l *Limits) copyNotificationIntegrationLimits(defaults NotificationRateLimitMap) { @@ -388,9 +398,7 @@ func (o *Overrides) MaxChunksPerQueryFromStore(userID string) int { return o.getOverridesForUser(userID).MaxChunksPerQueryFromStore } -// MaxChunksPerQueryFromIngesters returns the maximum number of chunks allowed per query when fetching -// chunks from ingesters. -func (o *Overrides) MaxChunksPerQueryFromIngesters(userID string) int { +func (o *Overrides) MaxChunksPerQuery(userID string) int { return o.getOverridesForUser(userID).MaxChunksPerQuery } @@ -400,6 +408,12 @@ func (o *Overrides) MaxFetchedSeriesPerQuery(userID string) int { return o.getOverridesForUser(userID).MaxFetchedSeriesPerQuery } +// MaxFetchedChunkBytesPerQuery returns the maximum number of bytes for chunks allowed per query when fetching +// chunks from ingesters and blocks storage. +func (o *Overrides) MaxFetchedChunkBytesPerQuery(userID string) int { + return o.getOverridesForUser(userID).MaxFetchedChunkBytesPerQuery +} + // MaxQueryLookback returns the max lookback period of queries. func (o *Overrides) MaxQueryLookback(userID string) time.Duration { return time.Duration(o.getOverridesForUser(userID).MaxQueryLookback) @@ -599,6 +613,18 @@ func (o *Overrides) AlertmanagerMaxTemplateSize(userID string) int { return o.getOverridesForUser(userID).AlertmanagerMaxTemplateSizeBytes } +func (o *Overrides) AlertmanagerMaxDispatcherAggregationGroups(userID string) int { + return o.getOverridesForUser(userID).AlertmanagerMaxDispatcherAggregationGroups +} + +func (o *Overrides) AlertmanagerMaxAlertsCount(userID string) int { + return o.getOverridesForUser(userID).AlertmanagerMaxAlertsCount +} + +func (o *Overrides) AlertmanagerMaxAlertsSizeBytes(userID string) int { + return o.getOverridesForUser(userID).AlertmanagerMaxAlertsSizeBytes +} + func (o *Overrides) getOverridesForUser(userID string) *Limits { if o.tenantLimits != nil { l := o.tenantLimits.ByUserID(userID) diff --git a/vendor/github.com/go-openapi/runtime/.gitattributes b/vendor/github.com/go-openapi/runtime/.gitattributes new file mode 100644 index 000000000000..d207b1802b20 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/.gitattributes @@ -0,0 +1 @@ +*.go text eol=lf diff --git a/vendor/github.com/go-openapi/runtime/.golangci.yml b/vendor/github.com/go-openapi/runtime/.golangci.yml index 71629d4ddd70..90f38cf8484e 100644 --- a/vendor/github.com/go-openapi/runtime/.golangci.yml +++ b/vendor/github.com/go-openapi/runtime/.golangci.yml @@ -13,7 +13,6 @@ linters-settings: min-len: 2 min-occurrences: 4 linters: - enable-all: true disable: - maligned - lll @@ -40,3 +39,5 @@ linters: - godot - errorlint - noctx + - interfacer + - nilerr diff --git a/vendor/github.com/go-openapi/runtime/.travis.yml b/vendor/github.com/go-openapi/runtime/.travis.yml index 78cdc892fa45..a716f63e9b92 100644 --- a/vendor/github.com/go-openapi/runtime/.travis.yml +++ b/vendor/github.com/go-openapi/runtime/.travis.yml @@ -1,7 +1,6 @@ after_success: - bash <(curl -s https://codecov.io/bash) go: -- 1.14.x - 1.x install: - GO111MODULE=off go get -u gotest.tools/gotestsum diff --git a/vendor/github.com/go-openapi/runtime/bytestream.go b/vendor/github.com/go-openapi/runtime/bytestream.go index 4459025b9279..6601a7797d34 100644 --- a/vendor/github.com/go-openapi/runtime/bytestream.go +++ b/vendor/github.com/go-openapi/runtime/bytestream.go @@ -129,6 +129,11 @@ func ByteStreamProducer(opts ...byteStreamOpt) Producer { } if data != nil { + if str, ok := data.(string); ok { + _, err := writer.Write([]byte(str)) + return err + } + if e, ok := data.(error); ok { _, err := writer.Write([]byte(e.Error())) return err diff --git a/vendor/github.com/go-openapi/swag/.golangci.yml b/vendor/github.com/go-openapi/swag/.golangci.yml index 813c47aa6436..842ac1c095c4 100644 --- a/vendor/github.com/go-openapi/swag/.golangci.yml +++ b/vendor/github.com/go-openapi/swag/.golangci.yml @@ -37,3 +37,5 @@ linters: - gci - gocognit - paralleltest + - thelper + - ifshort diff --git a/vendor/github.com/go-redis/redis/v8/.golangci.yml b/vendor/github.com/go-redis/redis/v8/.golangci.yml index 2132eee96f2b..d15b5ac5871a 100644 --- a/vendor/github.com/go-redis/redis/v8/.golangci.yml +++ b/vendor/github.com/go-redis/redis/v8/.golangci.yml @@ -17,5 +17,10 @@ linters: - gomnd - goerr113 - exhaustive - - gofumpt - nestif + - nlreturn + - exhaustivestruct + - wrapcheck + - errorlint + - cyclop + - forcetypeassert diff --git a/vendor/github.com/go-redis/redis/v8/.travis.yml b/vendor/github.com/go-redis/redis/v8/.travis.yml deleted file mode 100644 index adedd8df4e46..000000000000 --- a/vendor/github.com/go-redis/redis/v8/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -dist: xenial -language: go - -services: - - redis-server - -go: - - 1.14.x - - 1.15.x - - tip - -matrix: - allow_failures: - - go: tip - -go_import_path: github.com/go-redis/redis - -before_install: - - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- - -b $(go env GOPATH)/bin v1.28.3 diff --git a/vendor/github.com/go-redis/redis/v8/CHANGELOG.md b/vendor/github.com/go-redis/redis/v8/CHANGELOG.md index d0c4c8c1cb32..6b540a4f180f 100644 --- a/vendor/github.com/go-redis/redis/v8/CHANGELOG.md +++ b/vendor/github.com/go-redis/redis/v8/CHANGELOG.md @@ -1,10 +1,38 @@ # Changelog -> :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev) +> :heart: +> [**Uptrace.dev** - All-in-one tool to optimize performance and monitor errors & logs](https://uptrace.dev) -## v8 +## v8.9 + +- Changed `PubSub.Channel` to only rely on `Ping` result. You can now use `WithChannelSize`, + `WithChannelHealthCheckInterval`, and `WithChannelSendTimeout` to override default settings. + +## v8.8 + +- To make updating easier, extra modules now have the same version as go-redis does. That means that + you need to update your imports: + +``` +github.com/go-redis/redis/extra/redisotel -> github.com/go-redis/redis/extra/redisotel/v8 +github.com/go-redis/redis/extra/rediscensus -> github.com/go-redis/redis/extra/rediscensus/v8 +``` + +## v8.5 -- Documentation at https://redis.uptrace.dev/ +- [knadh](https://github.com/knadh) contributed long-awaited ability to scan Redis Hash into a + struct: + +```go +err := rdb.HGetAll(ctx, "hash").Scan(&data) + +err := rdb.MGet(ctx, "key1", "key2").Scan(&data) +``` + +- Please check [redismock](https://github.com/go-redis/redismock) by + [monkey92t](https://github.com/monkey92t) if you are looking for mocking Redis Client. + +## v8 - All commands require `context.Context` as a first argument, e.g. `rdb.Ping(ctx)`. If you are not using `context.Context` yet, the simplest option is to define global package variable diff --git a/vendor/github.com/go-redis/redis/v8/Makefile b/vendor/github.com/go-redis/redis/v8/Makefile index 49e4c96f068b..5501164f96f1 100644 --- a/vendor/github.com/go-redis/redis/v8/Makefile +++ b/vendor/github.com/go-redis/redis/v8/Makefile @@ -1,10 +1,9 @@ -all: testdeps +test: testdeps go test ./... go test ./... -short -race go test ./... -run=NONE -bench=. -benchmem env GOOS=linux GOARCH=386 go test ./... go vet - golangci-lint run testdeps: testdata/redis/src/redis-server @@ -15,7 +14,13 @@ bench: testdeps testdata/redis: mkdir -p $@ - wget -qO- http://download.redis.io/redis-stable.tar.gz | tar xvz --strip-components=1 -C $@ + wget -qO- https://download.redis.io/releases/redis-6.2.1.tar.gz | tar xvz --strip-components=1 -C $@ testdata/redis/src/redis-server: testdata/redis cd $< && make all + +tag: + git tag $(VERSION) + git tag extra/rediscmd/$(VERSION) + git tag extra/redisotel/$(VERSION) + git tag extra/rediscensus/$(VERSION) diff --git a/vendor/github.com/go-redis/redis/v8/README.md b/vendor/github.com/go-redis/redis/v8/README.md index 52cc756705eb..e58d867df9c7 100644 --- a/vendor/github.com/go-redis/redis/v8/README.md +++ b/vendor/github.com/go-redis/redis/v8/README.md @@ -1,25 +1,28 @@ +

+ + All-in-one tool to optimize performance and monitor errors & logs + +

+ # Redis client for Golang -[![Build Status](https://travis-ci.org/go-redis/redis.png?branch=master)](https://travis-ci.org/go-redis/redis) +![build workflow](https://github.com/go-redis/redis/actions/workflows/build.yml/badge.svg) [![PkgGoDev](https://pkg.go.dev/badge/github.com/go-redis/redis/v8)](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc) [![Documentation](https://img.shields.io/badge/redis-documentation-informational)](https://redis.uptrace.dev/) -[![Chat](https://discordapp.com/api/guilds/756530933771010068/widget.png)](https://discord.gg/ZQJDR3R) - -> :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev) +[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj) -- [Docs](https://redis.uptrace.dev) +- Join [Discord](https://discord.gg/rWtp5Aj) to ask questions. +- [Documentation](https://redis.uptrace.dev) - [Reference](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc) - [Examples](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples) -- [RealWorld example app](https://github.com/uptrace/go-realworld-example-app) -- Use [Discord](https://discord.gg/ZQJDR3R) or [stackoverflow](https://stackoverflow.com/) to ask - questions. +- [RealWorld example app](https://github.com/uptrace/go-treemux-realworld-example-app) ## Ecosystem -- [redisext](https://github.com/go-redis/redisext) - tracing using OpenTelemetryHook. +- [Redis Mock](https://github.com/go-redis/redismock). +- [Distributed Locks](https://github.com/bsm/redislock). - [Redis Cache](https://github.com/go-redis/cache). - [Rate limiting](https://github.com/go-redis/redis_rate). -- [Distributed Locks](https://github.com/bsm/redislock). ## Features @@ -39,23 +42,20 @@ - [Ring](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewRing). - [Instrumentation](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#ex-package--Instrumentation). -API docs: https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc. Examples: -https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples. - ## Installation -go-redis requires a Go version with [Modules](https://github.com/golang/go/wiki/Modules) support and -uses import versioning. So please make sure to initialize a Go module before installing go-redis: +go-redis supports 2 last Go versions and requires a Go version with +[modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go +module: ```shell go mod init github.com/my/repo -go get github.com/go-redis/redis/v8 ``` -Import: +And then install go-redis/v8 (note _v8_ in the import; omitting it is a popular mistake): -```go -import "github.com/go-redis/redis/v8" +```shell +go get github.com/go-redis/redis/v8 ``` ## Quickstart @@ -68,24 +68,13 @@ import ( var ctx = context.Background() -func ExampleNewClient() { - rdb := redis.NewClient(&redis.Options{ - Addr: "localhost:6379", - Password: "", // no password set - DB: 0, // use default DB - }) - - pong, err := rdb.Ping(ctx).Result() - fmt.Println(pong, err) - // Output: PONG -} - func ExampleClient() { rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB }) + err := rdb.Set(ctx, "key", "value", 0).Err() if err != nil { panic(err) @@ -110,11 +99,6 @@ func ExampleClient() { } ``` -## Howto - -Please go through [examples](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples) -to get an idea how to use this package. - ## Look and feel Some corner cases: @@ -150,8 +134,34 @@ vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello") res, err := rdb.Do(ctx, "set", "key", "value").Result() ``` +## Run the test + +go-redis will start a redis-server and run the test cases. + +The paths of redis-server bin file and redis config file are defined in `main_test.go`: + +``` +var ( + redisServerBin, _ = filepath.Abs(filepath.Join("testdata", "redis", "src", "redis-server")) + redisServerConf, _ = filepath.Abs(filepath.Join("testdata", "redis", "redis.conf")) +) +``` + +For local testing, you can change the variables to refer to your local files, or create a soft link +to the corresponding folder for redis-server and copy the config file to `testdata/redis/`: + +``` +ln -s /usr/bin/redis-server ./go-redis/testdata/redis/src +cp ./go-redis/testdata/redis.conf ./go-redis/testdata/redis/ +``` + +Lastly, run: + +``` +go test +``` + ## See also -- [Golang PostgreSQL ORM](https://github.com/go-pg/pg) -- [Golang msgpack](https://github.com/vmihailenco/msgpack) -- [Golang message task queue](https://github.com/vmihailenco/taskq) +- [Fast and flexible ORM](https://github.com/uptrace/bun) +- [msgpack for Go](https://github.com/vmihailenco/msgpack) diff --git a/vendor/github.com/go-redis/redis/v8/cluster.go b/vendor/github.com/go-redis/redis/v8/cluster.go index a6ce5c58462e..e5d49ddee744 100644 --- a/vendor/github.com/go-redis/redis/v8/cluster.go +++ b/vendor/github.com/go-redis/redis/v8/cluster.go @@ -86,7 +86,7 @@ func (opt *ClusterOptions) init() { opt.MaxRedirects = 3 } - if (opt.RouteByLatency || opt.RouteRandomly) && opt.ClusterSlots == nil { + if opt.RouteByLatency || opt.RouteRandomly { opt.ReadOnly = true } @@ -153,9 +153,13 @@ func (opt *ClusterOptions) clientOptions() *Options { IdleTimeout: opt.IdleTimeout, IdleCheckFrequency: disableIdleCheck, - readOnly: opt.ReadOnly, - TLSConfig: opt.TLSConfig, + // If ClusterSlots is populated, then we probably have an artificial + // cluster whose nodes are not in clustering mode (otherwise there isn't + // much use for ClusterSlots config). This means we cannot execute the + // READONLY command against that node -- setting readOnly to false in such + // situations in the options below will prevent that from happening. + readOnly: opt.ReadOnly && opt.ClusterSlots == nil, } } @@ -291,8 +295,9 @@ func (c *clusterNodes) Close() error { func (c *clusterNodes) Addrs() ([]string, error) { var addrs []string + c.mu.RLock() - closed := c.closed + closed := c.closed //nolint:ifshort if !closed { if len(c.activeAddrs) > 0 { addrs = c.activeAddrs @@ -628,14 +633,14 @@ func (c *clusterStateHolder) Reload(ctx context.Context) (*clusterState, error) return state, nil } -func (c *clusterStateHolder) LazyReload(ctx context.Context) { +func (c *clusterStateHolder) LazyReload() { if !atomic.CompareAndSwapUint32(&c.reloading, 0, 1) { return } go func() { defer atomic.StoreUint32(&c.reloading, 0) - _, err := c.Reload(ctx) + _, err := c.Reload(context.Background()) if err != nil { return } @@ -645,14 +650,15 @@ func (c *clusterStateHolder) LazyReload(ctx context.Context) { func (c *clusterStateHolder) Get(ctx context.Context) (*clusterState, error) { v := c.state.Load() - if v != nil { - state := v.(*clusterState) - if time.Since(state.createdAt) > 10*time.Second { - c.LazyReload(ctx) - } - return state, nil + if v == nil { + return c.Reload(ctx) + } + + state := v.(*clusterState) + if time.Since(state.createdAt) > 10*time.Second { + c.LazyReload() } - return c.Reload(ctx) + return state, nil } func (c *clusterStateHolder) ReloadOrGet(ctx context.Context) (*clusterState, error) { @@ -728,7 +734,7 @@ func (c *ClusterClient) Options() *ClusterOptions { // ReloadState reloads cluster state. If available it calls ClusterSlots func // to get cluster slots information. func (c *ClusterClient) ReloadState(ctx context.Context) { - c.state.LazyReload(ctx) + c.state.LazyReload() } // Close closes the cluster client, releasing any open resources. @@ -789,7 +795,7 @@ func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error { } if isReadOnly := isReadOnlyError(lastErr); isReadOnly || lastErr == pool.ErrClosed { if isReadOnly { - c.state.LazyReload(ctx) + c.state.LazyReload() } node = nil continue @@ -1224,7 +1230,7 @@ func (c *ClusterClient) checkMovedErr( } if moved { - c.state.LazyReload(ctx) + c.state.LazyReload() failedCmds.Add(node, cmd) return true } @@ -1252,10 +1258,13 @@ func (c *ClusterClient) TxPipelined(ctx context.Context, fn func(Pipeliner) erro } func (c *ClusterClient) processTxPipeline(ctx context.Context, cmds []Cmder) error { - return c.hooks.processPipeline(ctx, cmds, c._processTxPipeline) + return c.hooks.processTxPipeline(ctx, cmds, c._processTxPipeline) } func (c *ClusterClient) _processTxPipeline(ctx context.Context, cmds []Cmder) error { + // Trim multi .. exec. + cmds = cmds[1 : len(cmds)-1] + state, err := c.state.Get(ctx) if err != nil { setCmdsErr(cmds, err) @@ -1291,6 +1300,7 @@ func (c *ClusterClient) _processTxPipeline(ctx context.Context, cmds []Cmder) er if err == nil { return } + if attempt < c.opt.MaxRedirects { if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil { setCmdsErr(cmds, err) @@ -1406,7 +1416,7 @@ func (c *ClusterClient) cmdsMoved( } if moved { - c.state.LazyReload(ctx) + c.state.LazyReload() for _, cmd := range cmds { failedCmds.Add(node, cmd) } @@ -1464,7 +1474,7 @@ func (c *ClusterClient) Watch(ctx context.Context, fn func(*Tx) error, keys ...s if isReadOnly := isReadOnlyError(err); isReadOnly || err == pool.ErrClosed { if isReadOnly { - c.state.LazyReload(ctx) + c.state.LazyReload() } node, err = c.slotMasterNode(ctx, slot) if err != nil { @@ -1631,7 +1641,7 @@ func (c *ClusterClient) cmdNode( return nil, err } - if (c.opt.RouteByLatency || c.opt.RouteRandomly) && cmdInfo != nil && cmdInfo.ReadOnly { + if c.opt.ReadOnly && cmdInfo != nil && cmdInfo.ReadOnly { return c.slotReadOnlyNode(state, slot) } return state.slotMasterNode(slot) @@ -1655,6 +1665,35 @@ func (c *ClusterClient) slotMasterNode(ctx context.Context, slot int) (*clusterN return state.slotMasterNode(slot) } +// SlaveForKey gets a client for a replica node to run any command on it. +// This is especially useful if we want to run a particular lua script which has +// only read only commands on the replica. +// This is because other redis commands generally have a flag that points that +// they are read only and automatically run on the replica nodes +// if ClusterOptions.ReadOnly flag is set to true. +func (c *ClusterClient) SlaveForKey(ctx context.Context, key string) (*Client, error) { + state, err := c.state.Get(ctx) + if err != nil { + return nil, err + } + slot := hashtag.Slot(key) + node, err := c.slotReadOnlyNode(state, slot) + if err != nil { + return nil, err + } + return node.Client, err +} + +// MasterForKey return a client to the master node for a particular key. +func (c *ClusterClient) MasterForKey(ctx context.Context, key string) (*Client, error) { + slot := hashtag.Slot(key) + node, err := c.slotMasterNode(ctx, slot) + if err != nil { + return nil, err + } + return node.Client, err +} + func appendUniqueNode(nodes []*clusterNode, node *clusterNode) []*clusterNode { for _, n := range nodes { if n == node { diff --git a/vendor/github.com/go-redis/redis/v8/cluster_commands.go b/vendor/github.com/go-redis/redis/v8/cluster_commands.go index 1f0bae067ae6..336ea98dd7ab 100644 --- a/vendor/github.com/go-redis/redis/v8/cluster_commands.go +++ b/vendor/github.com/go-redis/redis/v8/cluster_commands.go @@ -2,6 +2,7 @@ package redis import ( "context" + "sync" "sync/atomic" ) @@ -23,3 +24,76 @@ func (c *ClusterClient) DBSize(ctx context.Context) *IntCmd { cmd.val = size return cmd } + +func (c *ClusterClient) ScriptLoad(ctx context.Context, script string) *StringCmd { + cmd := NewStringCmd(ctx, "script", "load", script) + mu := &sync.Mutex{} + err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error { + val, err := shard.ScriptLoad(ctx, script).Result() + if err != nil { + return err + } + + mu.Lock() + if cmd.Val() == "" { + cmd.val = val + } + mu.Unlock() + + return nil + }) + if err != nil { + cmd.SetErr(err) + } + + return cmd +} + +func (c *ClusterClient) ScriptFlush(ctx context.Context) *StatusCmd { + cmd := NewStatusCmd(ctx, "script", "flush") + _ = c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error { + shard.ScriptFlush(ctx) + + return nil + }) + + return cmd +} + +func (c *ClusterClient) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd { + args := make([]interface{}, 2+len(hashes)) + args[0] = "script" + args[1] = "exists" + for i, hash := range hashes { + args[2+i] = hash + } + cmd := NewBoolSliceCmd(ctx, args...) + + result := make([]bool, len(hashes)) + for i := range result { + result[i] = true + } + + mu := &sync.Mutex{} + err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error { + val, err := shard.ScriptExists(ctx, hashes...).Result() + if err != nil { + return err + } + + mu.Lock() + for i, v := range val { + result[i] = result[i] && v + } + mu.Unlock() + + return nil + }) + if err != nil { + cmd.SetErr(err) + } + + cmd.val = result + + return cmd +} diff --git a/vendor/github.com/go-redis/redis/v8/command.go b/vendor/github.com/go-redis/redis/v8/command.go index 5dd553325037..9a3018d3b4f0 100644 --- a/vendor/github.com/go-redis/redis/v8/command.go +++ b/vendor/github.com/go-redis/redis/v8/command.go @@ -8,6 +8,7 @@ import ( "time" "github.com/go-redis/redis/v8/internal" + "github.com/go-redis/redis/v8/internal/hscan" "github.com/go-redis/redis/v8/internal/proto" "github.com/go-redis/redis/v8/internal/util" ) @@ -371,6 +372,26 @@ func (cmd *SliceCmd) String() string { return cmdString(cmd, cmd.val) } +// Scan scans the results from the map into a destination struct. The map keys +// are matched in the Redis struct fields by the `redis:"field"` tag. +func (cmd *SliceCmd) Scan(dst interface{}) error { + if cmd.err != nil { + return cmd.err + } + + // Pass the list of keys and values. + // Skip the first two args for: HMGET key + var args []interface{} + if cmd.args[0] == "hmget" { + args = cmd.args[2:] + } else { + // Otherwise, it's: MGET field field ... + args = cmd.args[1:] + } + + return hscan.Scan(dst, args, cmd.val) +} + func (cmd *SliceCmd) readReply(rd *proto.Reader) error { v, err := rd.ReadArrayReply(sliceParser) if err != nil { @@ -689,6 +710,13 @@ func (cmd *StringCmd) Bytes() ([]byte, error) { return util.StringToBytes(cmd.val), cmd.err } +func (cmd *StringCmd) Bool() (bool, error) { + if cmd.err != nil { + return false, cmd.err + } + return strconv.ParseBool(cmd.val) +} + func (cmd *StringCmd) Int() (int, error) { if cmd.err != nil { return 0, cmd.err @@ -789,6 +817,55 @@ func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) { //------------------------------------------------------------------------------ +type FloatSliceCmd struct { + baseCmd + + val []float64 +} + +var _ Cmder = (*FloatSliceCmd)(nil) + +func NewFloatSliceCmd(ctx context.Context, args ...interface{}) *FloatSliceCmd { + return &FloatSliceCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, + } +} + +func (cmd *FloatSliceCmd) Val() []float64 { + return cmd.val +} + +func (cmd *FloatSliceCmd) Result() ([]float64, error) { + return cmd.val, cmd.err +} + +func (cmd *FloatSliceCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *FloatSliceCmd) readReply(rd *proto.Reader) error { + _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { + cmd.val = make([]float64, n) + for i := 0; i < len(cmd.val); i++ { + switch num, err := rd.ReadFloatReply(); { + case err == Nil: + cmd.val[i] = 0 + case err != nil: + return nil, err + default: + cmd.val[i] = num + } + } + return nil, nil + }) + return err +} + +//------------------------------------------------------------------------------ + type StringSliceCmd struct { baseCmd @@ -917,6 +994,27 @@ func (cmd *StringStringMapCmd) String() string { return cmdString(cmd, cmd.val) } +// Scan scans the results from the map into a destination struct. The map keys +// are matched in the Redis struct fields by the `redis:"field"` tag. +func (cmd *StringStringMapCmd) Scan(dst interface{}) error { + if cmd.err != nil { + return cmd.err + } + + strct, err := hscan.Struct(dst) + if err != nil { + return err + } + + for k, v := range cmd.val { + if err := strct.Scan(k, v); err != nil { + return err + } + } + + return nil +} + func (cmd *StringStringMapCmd) readReply(rd *proto.Reader) error { _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { cmd.val = make(map[string]string, n/2) @@ -1403,6 +1501,103 @@ func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error { //------------------------------------------------------------------------------ +type XInfoConsumersCmd struct { + baseCmd + val []XInfoConsumer +} + +type XInfoConsumer struct { + Name string + Pending int64 + Idle int64 +} + +var _ Cmder = (*XInfoConsumersCmd)(nil) + +func NewXInfoConsumersCmd(ctx context.Context, stream string, group string) *XInfoConsumersCmd { + return &XInfoConsumersCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: []interface{}{"xinfo", "consumers", stream, group}, + }, + } +} + +func (cmd *XInfoConsumersCmd) Val() []XInfoConsumer { + return cmd.val +} + +func (cmd *XInfoConsumersCmd) Result() ([]XInfoConsumer, error) { + return cmd.val, cmd.err +} + +func (cmd *XInfoConsumersCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *XInfoConsumersCmd) readReply(rd *proto.Reader) error { + n, err := rd.ReadArrayLen() + if err != nil { + return err + } + + cmd.val = make([]XInfoConsumer, n) + + for i := 0; i < n; i++ { + cmd.val[i], err = readXConsumerInfo(rd) + if err != nil { + return err + } + } + + return nil +} + +func readXConsumerInfo(rd *proto.Reader) (XInfoConsumer, error) { + var consumer XInfoConsumer + + n, err := rd.ReadArrayLen() + if err != nil { + return consumer, err + } + if n != 6 { + return consumer, fmt.Errorf("redis: got %d elements in XINFO CONSUMERS reply, wanted 6", n) + } + + for i := 0; i < 3; i++ { + key, err := rd.ReadString() + if err != nil { + return consumer, err + } + + val, err := rd.ReadString() + if err != nil { + return consumer, err + } + + switch key { + case "name": + consumer.Name = val + case "pending": + consumer.Pending, err = strconv.ParseInt(val, 0, 64) + if err != nil { + return consumer, err + } + case "idle": + consumer.Idle, err = strconv.ParseInt(val, 0, 64) + if err != nil { + return consumer, err + } + default: + return consumer, fmt.Errorf("redis: unexpected content %s in XINFO CONSUMERS reply", key) + } + } + + return consumer, nil +} + +//------------------------------------------------------------------------------ + type XInfoGroupsCmd struct { baseCmd val []XInfoGroup @@ -1574,8 +1769,14 @@ func xStreamInfoParser(rd *proto.Reader, n int64) (interface{}, error) { info.LastGeneratedID, err = rd.ReadString() case "first-entry": info.FirstEntry, err = readXMessage(rd) + if err == Nil { + err = nil + } case "last-entry": info.LastEntry, err = readXMessage(rd) + if err == Nil { + err = nil + } default: return nil, fmt.Errorf("redis: unexpected content %s "+ "in XINFO STREAM reply", key) @@ -1589,6 +1790,302 @@ func xStreamInfoParser(rd *proto.Reader, n int64) (interface{}, error) { //------------------------------------------------------------------------------ +type XInfoStreamFullCmd struct { + baseCmd + val *XInfoStreamFull +} + +type XInfoStreamFull struct { + Length int64 + RadixTreeKeys int64 + RadixTreeNodes int64 + LastGeneratedID string + Entries []XMessage + Groups []XInfoStreamGroup +} + +type XInfoStreamGroup struct { + Name string + LastDeliveredID string + PelCount int64 + Pending []XInfoStreamGroupPending + Consumers []XInfoStreamConsumer +} + +type XInfoStreamGroupPending struct { + ID string + Consumer string + DeliveryTime time.Time + DeliveryCount int64 +} + +type XInfoStreamConsumer struct { + Name string + SeenTime time.Time + PelCount int64 + Pending []XInfoStreamConsumerPending +} + +type XInfoStreamConsumerPending struct { + ID string + DeliveryTime time.Time + DeliveryCount int64 +} + +var _ Cmder = (*XInfoStreamFullCmd)(nil) + +func NewXInfoStreamFullCmd(ctx context.Context, args ...interface{}) *XInfoStreamFullCmd { + return &XInfoStreamFullCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, + } +} + +func (cmd *XInfoStreamFullCmd) Val() *XInfoStreamFull { + return cmd.val +} + +func (cmd *XInfoStreamFullCmd) Result() (*XInfoStreamFull, error) { + return cmd.val, cmd.err +} + +func (cmd *XInfoStreamFullCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *XInfoStreamFullCmd) readReply(rd *proto.Reader) error { + n, err := rd.ReadArrayLen() + if err != nil { + return err + } + if n != 12 { + return fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+ + "wanted 12", n) + } + + cmd.val = &XInfoStreamFull{} + + for i := 0; i < 6; i++ { + key, err := rd.ReadString() + if err != nil { + return err + } + + switch key { + case "length": + cmd.val.Length, err = rd.ReadIntReply() + case "radix-tree-keys": + cmd.val.RadixTreeKeys, err = rd.ReadIntReply() + case "radix-tree-nodes": + cmd.val.RadixTreeNodes, err = rd.ReadIntReply() + case "last-generated-id": + cmd.val.LastGeneratedID, err = rd.ReadString() + case "entries": + cmd.val.Entries, err = readXMessageSlice(rd) + case "groups": + cmd.val.Groups, err = readStreamGroups(rd) + default: + return fmt.Errorf("redis: unexpected content %s "+ + "in XINFO STREAM reply", key) + } + if err != nil { + return err + } + } + return nil +} + +func readStreamGroups(rd *proto.Reader) ([]XInfoStreamGroup, error) { + n, err := rd.ReadArrayLen() + if err != nil { + return nil, err + } + groups := make([]XInfoStreamGroup, 0, n) + for i := 0; i < n; i++ { + nn, err := rd.ReadArrayLen() + if err != nil { + return nil, err + } + if nn != 10 { + return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+ + "wanted 10", nn) + } + + group := XInfoStreamGroup{} + + for f := 0; f < 5; f++ { + key, err := rd.ReadString() + if err != nil { + return nil, err + } + + switch key { + case "name": + group.Name, err = rd.ReadString() + case "last-delivered-id": + group.LastDeliveredID, err = rd.ReadString() + case "pel-count": + group.PelCount, err = rd.ReadIntReply() + case "pending": + group.Pending, err = readXInfoStreamGroupPending(rd) + case "consumers": + group.Consumers, err = readXInfoStreamConsumers(rd) + default: + return nil, fmt.Errorf("redis: unexpected content %s "+ + "in XINFO STREAM reply", key) + } + + if err != nil { + return nil, err + } + } + + groups = append(groups, group) + } + + return groups, nil +} + +func readXInfoStreamGroupPending(rd *proto.Reader) ([]XInfoStreamGroupPending, error) { + n, err := rd.ReadArrayLen() + if err != nil { + return nil, err + } + + pending := make([]XInfoStreamGroupPending, 0, n) + + for i := 0; i < n; i++ { + nn, err := rd.ReadArrayLen() + if err != nil { + return nil, err + } + if nn != 4 { + return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+ + "wanted 4", nn) + } + + p := XInfoStreamGroupPending{} + + p.ID, err = rd.ReadString() + if err != nil { + return nil, err + } + + p.Consumer, err = rd.ReadString() + if err != nil { + return nil, err + } + + delivery, err := rd.ReadIntReply() + if err != nil { + return nil, err + } + p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond)) + + p.DeliveryCount, err = rd.ReadIntReply() + if err != nil { + return nil, err + } + + pending = append(pending, p) + } + + return pending, nil +} + +func readXInfoStreamConsumers(rd *proto.Reader) ([]XInfoStreamConsumer, error) { + n, err := rd.ReadArrayLen() + if err != nil { + return nil, err + } + + consumers := make([]XInfoStreamConsumer, 0, n) + + for i := 0; i < n; i++ { + nn, err := rd.ReadArrayLen() + if err != nil { + return nil, err + } + if nn != 8 { + return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+ + "wanted 8", nn) + } + + c := XInfoStreamConsumer{} + + for f := 0; f < 4; f++ { + cKey, err := rd.ReadString() + if err != nil { + return nil, err + } + + switch cKey { + case "name": + c.Name, err = rd.ReadString() + case "seen-time": + seen, err := rd.ReadIntReply() + if err != nil { + return nil, err + } + c.SeenTime = time.Unix(seen/1000, seen%1000*int64(time.Millisecond)) + case "pel-count": + c.PelCount, err = rd.ReadIntReply() + case "pending": + pendingNumber, err := rd.ReadArrayLen() + if err != nil { + return nil, err + } + + c.Pending = make([]XInfoStreamConsumerPending, 0, pendingNumber) + + for pn := 0; pn < pendingNumber; pn++ { + nn, err := rd.ReadArrayLen() + if err != nil { + return nil, err + } + if nn != 3 { + return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM reply,"+ + "wanted 3", nn) + } + + p := XInfoStreamConsumerPending{} + + p.ID, err = rd.ReadString() + if err != nil { + return nil, err + } + + delivery, err := rd.ReadIntReply() + if err != nil { + return nil, err + } + p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond)) + + p.DeliveryCount, err = rd.ReadIntReply() + if err != nil { + return nil, err + } + + c.Pending = append(c.Pending, p) + } + default: + return nil, fmt.Errorf("redis: unexpected content %s "+ + "in XINFO STREAM reply", cKey) + } + if err != nil { + return nil, err + } + } + consumers = append(consumers, c) + } + + return consumers, nil +} + +//------------------------------------------------------------------------------ + type ZSliceCmd struct { baseCmd diff --git a/vendor/github.com/go-redis/redis/v8/commands.go b/vendor/github.com/go-redis/redis/v8/commands.go index f4e6afc14753..9c6439047a59 100644 --- a/vendor/github.com/go-redis/redis/v8/commands.go +++ b/vendor/github.com/go-redis/redis/v8/commands.go @@ -67,6 +67,11 @@ func appendArg(dst []interface{}, arg interface{}) []interface{} { dst = append(dst, k, v) } return dst + case map[string]string: + for k, v := range arg { + dst = append(dst, k, v) + } + return dst default: return append(dst, arg) } @@ -117,6 +122,8 @@ type Cmdable interface { Get(ctx context.Context, key string) *StringCmd GetRange(ctx context.Context, key string, start, end int64) *StringCmd GetSet(ctx context.Context, key string, value interface{}) *StringCmd + GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd + GetDel(ctx context.Context, key string) *StringCmd Incr(ctx context.Context, key string) *IntCmd IncrBy(ctx context.Context, key string, value int64) *IntCmd IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd @@ -124,6 +131,9 @@ type Cmdable interface { MSet(ctx context.Context, values ...interface{}) *StatusCmd MSetNX(ctx context.Context, values ...interface{}) *BoolCmd Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd + SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd + // TODO: rename to SetEx + SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd @@ -140,6 +150,7 @@ type Cmdable interface { BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd + ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd @@ -157,6 +168,7 @@ type Cmdable interface { HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd HVals(ctx context.Context, key string) *StringSliceCmd + HRandField(ctx context.Context, key string, count int, withValues bool) *StringSliceCmd BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd @@ -167,6 +179,9 @@ type Cmdable interface { LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd LLen(ctx context.Context, key string) *IntCmd LPop(ctx context.Context, key string) *StringCmd + LPopCount(ctx context.Context, key string, count int) *StringSliceCmd + LPos(ctx context.Context, key string, value string, args LPosArgs) *IntCmd + LPosCount(ctx context.Context, key string, value string, count int64, args LPosArgs) *IntSliceCmd LPush(ctx context.Context, key string, values ...interface{}) *IntCmd LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd @@ -177,6 +192,7 @@ type Cmdable interface { RPopLPush(ctx context.Context, source, destination string) *StringCmd RPush(ctx context.Context, key string, values ...interface{}) *IntCmd RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd + LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd SCard(ctx context.Context, key string) *IntCmd @@ -185,6 +201,7 @@ type Cmdable interface { SInter(ctx context.Context, keys ...string) *StringSliceCmd SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd + SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd SMembers(ctx context.Context, key string) *StringSliceCmd SMembersMap(ctx context.Context, key string) *StringStructMapCmd SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd @@ -220,6 +237,7 @@ type Cmdable interface { XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd XInfoStream(ctx context.Context, key string) *XInfoStreamCmd + XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd @@ -237,6 +255,7 @@ type Cmdable interface { ZLexCount(ctx context.Context, key, min, max string) *IntCmd ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd + ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd @@ -257,6 +276,9 @@ type Cmdable interface { ZRevRank(ctx context.Context, key, member string) *IntCmd ZScore(ctx context.Context, key, member string) *FloatCmd ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd + ZRandMember(ctx context.Context, key string, count int, withScores bool) *StringSliceCmd + ZDiff(ctx context.Context, keys ...string) *StringSliceCmd + ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd PFCount(ctx context.Context, keys ...string) *IntCmd @@ -704,6 +726,33 @@ func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *Str return cmd } +// An expiration of zero removes the TTL associated with the key (i.e. GETEX key persist). +// Requires Redis >= 6.2.0. +func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd { + args := make([]interface{}, 0, 4) + args = append(args, "getex", key) + if expiration > 0 { + if usePrecise(expiration) { + args = append(args, "px", formatMs(ctx, expiration)) + } else { + args = append(args, "ex", formatSec(ctx, expiration)) + } + } else if expiration == 0 { + args = append(args, "persist") + } + + cmd := NewStringCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// redis-server version >= 6.2.0. +func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd { + cmd := NewStringCmd(ctx, "getdel", key) + _ = c(ctx, cmd) + return cmd +} + func (c cmdable) Incr(ctx context.Context, key string) *IntCmd { cmd := NewIntCmd(ctx, "incr", key) _ = c(ctx, cmd) @@ -784,6 +833,63 @@ func (c cmdable) Set(ctx context.Context, key string, value interface{}, expirat return cmd } +// SetArgs provides arguments for the SetArgs function. +type SetArgs struct { + // Mode can be `NX` or `XX` or empty. + Mode string + + // Zero `TTL` or `Expiration` means that the key has no expiration time. + TTL time.Duration + ExpireAt time.Time + + // When Get is true, the command returns the old value stored at key, or nil when key did not exist. + Get bool + + // KeepTTL is a Redis KEEPTTL option to keep existing TTL. + KeepTTL bool +} + +// SetArgs supports all the options that the SET command supports. +// It is the alternative to the Set function when you want +// to have more control over the options. +func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd { + args := []interface{}{"set", key, value} + + if a.KeepTTL { + args = append(args, "keepttl") + } + + if !a.ExpireAt.IsZero() { + args = append(args, "exat", a.ExpireAt.Unix()) + } + if a.TTL > 0 { + if usePrecise(a.TTL) { + args = append(args, "px", formatMs(ctx, a.TTL)) + } else { + args = append(args, "ex", formatSec(ctx, a.TTL)) + } + } + + if a.Mode != "" { + args = append(args, a.Mode) + } + + if a.Get { + args = append(args, "get") + } + + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// Redis `SETEX key expiration value` command. +func (c cmdable) SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd { + cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value) + _ = c(ctx, cmd) + return cmd +} + // Redis `SET key value [expiration] NX` command. // // Zero expiration means the key has no expiration time. @@ -955,6 +1061,22 @@ func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count in return cmd } +func (c cmdable) ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd { + args := []interface{}{"scan", cursor} + if match != "" { + args = append(args, "match", match) + } + if count > 0 { + args = append(args, "count", count) + } + if keyType != "" { + args = append(args, "type", keyType) + } + cmd := NewScanCmd(ctx, c, args...) + _ = c(ctx, cmd) + return cmd +} + func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd { args := []interface{}{"sscan", key, cursor} if match != "" { @@ -1103,6 +1225,21 @@ func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd { return cmd } +// redis-server version >= 6.2.0. +func (c cmdable) HRandField(ctx context.Context, key string, count int, withValues bool) *StringSliceCmd { + args := make([]interface{}, 0, 4) + + // Although count=0 is meaningless, redis accepts count=0. + args = append(args, "hrandfield", key, count) + if withValues { + args = append(args, "withvalues") + } + + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + //------------------------------------------------------------------------------ func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd { @@ -1180,6 +1317,43 @@ func (c cmdable) LPop(ctx context.Context, key string) *StringCmd { return cmd } +func (c cmdable) LPopCount(ctx context.Context, key string, count int) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, "lpop", key, count) + _ = c(ctx, cmd) + return cmd +} + +type LPosArgs struct { + Rank, MaxLen int64 +} + +func (c cmdable) LPos(ctx context.Context, key string, value string, a LPosArgs) *IntCmd { + args := []interface{}{"lpos", key, value} + if a.Rank != 0 { + args = append(args, "rank", a.Rank) + } + if a.MaxLen != 0 { + args = append(args, "maxlen", a.MaxLen) + } + + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) LPosCount(ctx context.Context, key string, value string, count int64, a LPosArgs) *IntSliceCmd { + args := []interface{}{"lpos", key, value, "count", count} + if a.Rank != 0 { + args = append(args, "rank", a.Rank) + } + if a.MaxLen != 0 { + args = append(args, "maxlen", a.MaxLen) + } + cmd := NewIntSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(values)) args[0] = "lpush" @@ -1268,6 +1442,12 @@ func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) return cmd } +func (c cmdable) LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd { + cmd := NewStringCmd(ctx, "lmove", source, destination, srcpos, destpos) + _ = c(ctx, cmd) + return cmd +} + //------------------------------------------------------------------------------ func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd { @@ -1338,6 +1518,17 @@ func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) return cmd } +// Redis `SMISMEMBER key member [member ...]` command. +func (c cmdable) SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd { + args := make([]interface{}, 2, 2+len(members)) + args[0] = "smismember" + args[1] = key + args = appendArgs(args, members) + cmd := NewBoolSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + // Redis `SMEMBERS key` command output as a slice. func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd { cmd := NewStringSliceCmd(ctx, "smembers", key) @@ -1629,6 +1820,7 @@ func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCm type XPendingExtArgs struct { Stream string Group string + Idle time.Duration Start string End string Count int64 @@ -1636,8 +1828,12 @@ type XPendingExtArgs struct { } func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd { - args := make([]interface{}, 0, 7) - args = append(args, "xpending", a.Stream, a.Group, a.Start, a.End, a.Count) + args := make([]interface{}, 0, 9) + args = append(args, "xpending", a.Stream, a.Group) + if a.Idle != 0 { + args = append(args, "idle", formatMs(ctx, a.Idle)) + } + args = append(args, a.Start, a.End, a.Count) if a.Consumer != "" { args = append(args, a.Consumer) } @@ -1694,6 +1890,12 @@ func (c cmdable) XTrimApprox(ctx context.Context, key string, maxLen int64) *Int return cmd } +func (c cmdable) XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd { + cmd := NewXInfoConsumersCmd(ctx, key, group) + _ = c(ctx, cmd) + return cmd +} + func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd { cmd := NewXInfoGroupsCmd(ctx, key) _ = c(ctx, cmd) @@ -1706,6 +1908,19 @@ func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd { return cmd } +// XInfoStreamFull XINFO STREAM FULL [COUNT count] +// redis-server >= 6.0. +func (c cmdable) XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd { + args := make([]interface{}, 0, 6) + args = append(args, "xinfo", "stream", key, "full") + if count > 0 { + args = append(args, "count", count) + } + cmd := NewXInfoStreamFullCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + //------------------------------------------------------------------------------ // Z represents sorted set member. @@ -1873,12 +2088,10 @@ func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, mem } func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd { - args := make([]interface{}, 3+len(store.Keys)) - args[0] = "zinterstore" - args[1] = destination - args[2] = len(store.Keys) - for i, key := range store.Keys { - args[3+i] = key + args := make([]interface{}, 0, 3+len(store.Keys)) + args = append(args, "zinterstore", destination, len(store.Keys)) + for _, key := range store.Keys { + args = append(args, key) } if len(store.Weights) > 0 { args = append(args, "weights") @@ -1895,6 +2108,18 @@ func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZSt return cmd } +func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd { + args := make([]interface{}, 2+len(members)) + args[0] = "zmscore" + args[1] = key + for i, member := range members { + args[2+i] = member + } + cmd := NewFloatSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd { args := []interface{}{ "zpopmax", @@ -2109,12 +2334,10 @@ func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd { } func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd { - args := make([]interface{}, 3+len(store.Keys)) - args[0] = "zunionstore" - args[1] = dest - args[2] = len(store.Keys) - for i, key := range store.Keys { - args[3+i] = key + args := make([]interface{}, 0, 3+len(store.Keys)) + args = append(args, "zunionstore", dest, len(store.Keys)) + for _, key := range store.Keys { + args = append(args, key) } if len(store.Weights) > 0 { args = append(args, "weights") @@ -2132,6 +2355,50 @@ func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *I return cmd } +// redis-server version >= 6.2.0. +func (c cmdable) ZRandMember(ctx context.Context, key string, count int, withScores bool) *StringSliceCmd { + args := make([]interface{}, 0, 4) + + // Although count=0 is meaningless, redis accepts count=0. + args = append(args, "zrandmember", key, count) + if withScores { + args = append(args, "withscores") + } + + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// redis-server version >= 6.2.0. +func (c cmdable) ZDiff(ctx context.Context, keys ...string) *StringSliceCmd { + args := make([]interface{}, 2+len(keys)) + args[0] = "zdiff" + args[1] = len(keys) + for i, key := range keys { + args[i+2] = key + } + + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// redis-server version >= 6.2.0. +func (c cmdable) ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd { + args := make([]interface{}, 3+len(keys)) + args[0] = "zdiff" + args[1] = len(keys) + for i, key := range keys { + args[i+2] = key + } + args[len(keys)+2] = "withscores" + + cmd := NewZSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + //------------------------------------------------------------------------------ func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd { diff --git a/vendor/github.com/go-redis/redis/v8/error.go b/vendor/github.com/go-redis/redis/v8/error.go index d29c0c99feee..ad9e173ea742 100644 --- a/vendor/github.com/go-redis/redis/v8/error.go +++ b/vendor/github.com/go-redis/redis/v8/error.go @@ -10,6 +10,7 @@ import ( "github.com/go-redis/redis/v8/internal/proto" ) +// ErrClosed performs any operation on the closed client will return this error. var ErrClosed = pool.ErrClosed type Error interface { @@ -52,6 +53,9 @@ func shouldRetry(err error, retryTimeout bool) bool { if strings.HasPrefix(s, "CLUSTERDOWN ") { return true } + if strings.HasPrefix(s, "TRYAGAIN ") { + return true + } return false } @@ -62,8 +66,11 @@ func isRedisError(err error) bool { } func isBadConn(err error, allowTimeout bool) bool { - if err == nil { + switch err { + case nil: return false + case context.Canceled, context.DeadlineExceeded: + return true } if isRedisError(err) { diff --git a/vendor/github.com/go-redis/redis/v8/go.mod b/vendor/github.com/go-redis/redis/v8/go.mod index 21c0bb85b0ef..bfe914803dec 100644 --- a/vendor/github.com/go-redis/redis/v8/go.mod +++ b/vendor/github.com/go-redis/redis/v8/go.mod @@ -1,11 +1,13 @@ module github.com/go-redis/redis/v8 -go 1.11 +go 1.13 require ( github.com/cespare/xxhash/v2 v2.1.1 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f - github.com/onsi/ginkgo v1.14.1 - github.com/onsi/gomega v1.10.2 - go.opentelemetry.io/otel v0.11.0 + github.com/onsi/ginkgo v1.15.0 + github.com/onsi/gomega v1.10.5 + go.opentelemetry.io/otel v0.20.0 + go.opentelemetry.io/otel/metric v0.20.0 + go.opentelemetry.io/otel/trace v0.20.0 ) diff --git a/vendor/github.com/go-redis/redis/v8/go.sum b/vendor/github.com/go-redis/redis/v8/go.sum index 82fcc1683b76..b8309364d9fa 100644 --- a/vendor/github.com/go-redis/redis/v8/go.sum +++ b/vendor/github.com/go-redis/redis/v8/go.sum @@ -18,45 +18,68 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= -github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= +github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= -github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E= -go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go b/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go index 2fc74ad1cd0b..b3a4f211e336 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go +++ b/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go @@ -60,7 +60,7 @@ func RandomSlot() int { return rand.Intn(slotNumber) } -// hashSlot returns a consistent slot number between 0 and 16383 +// Slot returns a consistent slot number between 0 and 16383 // for any given string key. func Slot(key string) int { if key == "" { diff --git a/vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go b/vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go new file mode 100644 index 000000000000..6f97f9287cb4 --- /dev/null +++ b/vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go @@ -0,0 +1,201 @@ +package hscan + +import ( + "errors" + "fmt" + "reflect" + "strconv" +) + +// decoderFunc represents decoding functions for default built-in types. +type decoderFunc func(reflect.Value, string) error + +var ( + // List of built-in decoders indexed by their numeric constant values (eg: reflect.Bool = 1). + decoders = []decoderFunc{ + reflect.Bool: decodeBool, + reflect.Int: decodeInt, + reflect.Int8: decodeInt8, + reflect.Int16: decodeInt16, + reflect.Int32: decodeInt32, + reflect.Int64: decodeInt64, + reflect.Uint: decodeUint, + reflect.Uint8: decodeUint8, + reflect.Uint16: decodeUint16, + reflect.Uint32: decodeUint32, + reflect.Uint64: decodeUint64, + reflect.Float32: decodeFloat32, + reflect.Float64: decodeFloat64, + reflect.Complex64: decodeUnsupported, + reflect.Complex128: decodeUnsupported, + reflect.Array: decodeUnsupported, + reflect.Chan: decodeUnsupported, + reflect.Func: decodeUnsupported, + reflect.Interface: decodeUnsupported, + reflect.Map: decodeUnsupported, + reflect.Ptr: decodeUnsupported, + reflect.Slice: decodeSlice, + reflect.String: decodeString, + reflect.Struct: decodeUnsupported, + reflect.UnsafePointer: decodeUnsupported, + } + + // Global map of struct field specs that is populated once for every new + // struct type that is scanned. This caches the field types and the corresponding + // decoder functions to avoid iterating through struct fields on subsequent scans. + globalStructMap = newStructMap() +) + +func Struct(dst interface{}) (StructValue, error) { + v := reflect.ValueOf(dst) + + // The dstination to scan into should be a struct pointer. + if v.Kind() != reflect.Ptr || v.IsNil() { + return StructValue{}, fmt.Errorf("redis.Scan(non-pointer %T)", dst) + } + + v = v.Elem() + if v.Kind() != reflect.Struct { + return StructValue{}, fmt.Errorf("redis.Scan(non-struct %T)", dst) + } + + return StructValue{ + spec: globalStructMap.get(v.Type()), + value: v, + }, nil +} + +// Scan scans the results from a key-value Redis map result set to a destination struct. +// The Redis keys are matched to the struct's field with the `redis` tag. +func Scan(dst interface{}, keys []interface{}, vals []interface{}) error { + if len(keys) != len(vals) { + return errors.New("args should have the same number of keys and vals") + } + + strct, err := Struct(dst) + if err != nil { + return err + } + + // Iterate through the (key, value) sequence. + for i := 0; i < len(vals); i++ { + key, ok := keys[i].(string) + if !ok { + continue + } + + val, ok := vals[i].(string) + if !ok { + continue + } + + if err := strct.Scan(key, val); err != nil { + return err + } + } + + return nil +} + +func decodeBool(f reflect.Value, s string) error { + b, err := strconv.ParseBool(s) + if err != nil { + return err + } + f.SetBool(b) + return nil +} + +func decodeInt8(f reflect.Value, s string) error { + return decodeNumber(f, s, 8) +} + +func decodeInt16(f reflect.Value, s string) error { + return decodeNumber(f, s, 16) +} + +func decodeInt32(f reflect.Value, s string) error { + return decodeNumber(f, s, 32) +} + +func decodeInt64(f reflect.Value, s string) error { + return decodeNumber(f, s, 64) +} + +func decodeInt(f reflect.Value, s string) error { + return decodeNumber(f, s, 0) +} + +func decodeNumber(f reflect.Value, s string, bitSize int) error { + v, err := strconv.ParseInt(s, 10, bitSize) + if err != nil { + return err + } + f.SetInt(v) + return nil +} + +func decodeUint8(f reflect.Value, s string) error { + return decodeUnsignedNumber(f, s, 8) +} + +func decodeUint16(f reflect.Value, s string) error { + return decodeUnsignedNumber(f, s, 16) +} + +func decodeUint32(f reflect.Value, s string) error { + return decodeUnsignedNumber(f, s, 32) +} + +func decodeUint64(f reflect.Value, s string) error { + return decodeUnsignedNumber(f, s, 64) +} + +func decodeUint(f reflect.Value, s string) error { + return decodeUnsignedNumber(f, s, 0) +} + +func decodeUnsignedNumber(f reflect.Value, s string, bitSize int) error { + v, err := strconv.ParseUint(s, 10, bitSize) + if err != nil { + return err + } + f.SetUint(v) + return nil +} + +func decodeFloat32(f reflect.Value, s string) error { + v, err := strconv.ParseFloat(s, 32) + if err != nil { + return err + } + f.SetFloat(v) + return nil +} + +// although the default is float64, but we better define it. +func decodeFloat64(f reflect.Value, s string) error { + v, err := strconv.ParseFloat(s, 64) + if err != nil { + return err + } + f.SetFloat(v) + return nil +} + +func decodeString(f reflect.Value, s string) error { + f.SetString(s) + return nil +} + +func decodeSlice(f reflect.Value, s string) error { + // []byte slice ([]uint8). + if f.Type().Elem().Kind() == reflect.Uint8 { + f.SetBytes([]byte(s)) + } + return nil +} + +func decodeUnsupported(v reflect.Value, s string) error { + return fmt.Errorf("redis.Scan(unsupported %s)", v.Type()) +} diff --git a/vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go b/vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go new file mode 100644 index 000000000000..1b233258df1c --- /dev/null +++ b/vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go @@ -0,0 +1,93 @@ +package hscan + +import ( + "fmt" + "reflect" + "strings" + "sync" +) + +// structMap contains the map of struct fields for target structs +// indexed by the struct type. +type structMap struct { + m sync.Map +} + +func newStructMap() *structMap { + return new(structMap) +} + +func (s *structMap) get(t reflect.Type) *structSpec { + if v, ok := s.m.Load(t); ok { + return v.(*structSpec) + } + + spec := newStructSpec(t, "redis") + s.m.Store(t, spec) + return spec +} + +//------------------------------------------------------------------------------ + +// structSpec contains the list of all fields in a target struct. +type structSpec struct { + m map[string]*structField +} + +func (s *structSpec) set(tag string, sf *structField) { + s.m[tag] = sf +} + +func newStructSpec(t reflect.Type, fieldTag string) *structSpec { + out := &structSpec{ + m: make(map[string]*structField), + } + + num := t.NumField() + for i := 0; i < num; i++ { + f := t.Field(i) + + tag := f.Tag.Get(fieldTag) + if tag == "" || tag == "-" { + continue + } + + tag = strings.Split(tag, ",")[0] + if tag == "" { + continue + } + + // Use the built-in decoder. + out.set(tag, &structField{index: i, fn: decoders[f.Type.Kind()]}) + } + + return out +} + +//------------------------------------------------------------------------------ + +// structField represents a single field in a target struct. +type structField struct { + index int + fn decoderFunc +} + +//------------------------------------------------------------------------------ + +type StructValue struct { + spec *structSpec + value reflect.Value +} + +func (s StructValue) Scan(key string, value string) error { + field, ok := s.spec.m[key] + if !ok { + return nil + } + if err := field.fn(s.value.Field(field.index), value); err != nil { + t := s.value.Type() + return fmt.Errorf("cannot scan redis.result %s into struct field %s.%s of type %s, error-%s", + value, t.Name(), t.Field(field.index).Name, t.Field(field.index).Type, err.Error()) + } + return nil +} diff --git a/vendor/github.com/go-redis/redis/v8/internal/instruments.go b/vendor/github.com/go-redis/redis/v8/internal/instruments.go index e837526d8946..49d6111e188b 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/instruments.go +++ b/vendor/github.com/go-redis/redis/v8/internal/instruments.go @@ -3,8 +3,8 @@ package internal import ( "context" - "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/metric" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/global" ) var ( diff --git a/vendor/github.com/go-redis/redis/v8/internal/internal.go b/vendor/github.com/go-redis/redis/v8/internal/internal.go index 735d6affd8b3..4a59c599be77 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/internal.go +++ b/vendor/github.com/go-redis/redis/v8/internal/internal.go @@ -15,6 +15,10 @@ func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration } d := minBackoff << uint(retry) + if d < minBackoff { + return maxBackoff + } + d = minBackoff + time.Duration(rand.Int63n(int64(d))) if d > maxBackoff || d < minBackoff { diff --git a/vendor/github.com/go-redis/redis/v8/internal/log.go b/vendor/github.com/go-redis/redis/v8/internal/log.go index 3810f9e4e7ac..c8b9213de48c 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/log.go +++ b/vendor/github.com/go-redis/redis/v8/internal/log.go @@ -19,6 +19,8 @@ func (l *logger) Printf(ctx context.Context, format string, v ...interface{}) { _ = l.log.Output(2, fmt.Sprintf(format, v...)) } +// Logger calls Output to print to the stderr. +// Arguments are handled in the manner of fmt.Print. var Logger Logging = &logger{ log: log.New(os.Stderr, "redis: ", log.LstdFlags|log.Lshortfile), } diff --git a/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go b/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go index b930a908800a..ee064c9fc97a 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go +++ b/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go @@ -9,7 +9,6 @@ import ( "github.com/go-redis/redis/v8/internal" "github.com/go-redis/redis/v8/internal/proto" - "go.opentelemetry.io/otel/api/trace" ) var noDeadline = time.Time{} @@ -66,41 +65,43 @@ func (cn *Conn) RemoteAddr() net.Addr { } func (cn *Conn) WithReader(ctx context.Context, timeout time.Duration, fn func(rd *proto.Reader) error) error { - return internal.WithSpan(ctx, "with_reader", func(ctx context.Context, span trace.Span) error { - if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil { - return internal.RecordError(ctx, err) - } - if err := fn(cn.rd); err != nil { - return internal.RecordError(ctx, err) - } - return nil - }) + ctx, span := internal.StartSpan(ctx, "redis.with_reader") + defer span.End() + + if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil { + return internal.RecordError(ctx, span, err) + } + if err := fn(cn.rd); err != nil { + return internal.RecordError(ctx, span, err) + } + return nil } func (cn *Conn) WithWriter( ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer) error, ) error { - return internal.WithSpan(ctx, "with_writer", func(ctx context.Context, span trace.Span) error { - if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil { - return internal.RecordError(ctx, err) - } + ctx, span := internal.StartSpan(ctx, "redis.with_writer") + defer span.End() - if cn.bw.Buffered() > 0 { - cn.bw.Reset(cn.netConn) - } + if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil { + return internal.RecordError(ctx, span, err) + } - if err := fn(cn.wr); err != nil { - return internal.RecordError(ctx, err) - } + if cn.bw.Buffered() > 0 { + cn.bw.Reset(cn.netConn) + } - if err := cn.bw.Flush(); err != nil { - return internal.RecordError(ctx, err) - } + if err := fn(cn.wr); err != nil { + return internal.RecordError(ctx, span, err) + } + + if err := cn.bw.Flush(); err != nil { + return internal.RecordError(ctx, span, err) + } - internal.WritesCounter.Add(ctx, 1) + internal.WritesCounter.Add(ctx, 1) - return nil - }) + return nil } func (cn *Conn) Close() error { diff --git a/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go b/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go index 355742bf3582..4d247b301048 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go +++ b/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go @@ -12,7 +12,10 @@ import ( ) var ( - ErrClosed = errors.New("redis: client is closed") + // ErrClosed performs any operation on the closed client will return this error. + ErrClosed = errors.New("redis: client is closed") + + // ErrPoolTimeout timed out waiting to get a connection from the connection pool. ErrPoolTimeout = errors.New("redis: connection pool timeout") ) @@ -228,8 +231,7 @@ func (p *ConnPool) Get(ctx context.Context) (*Conn, error) { return nil, ErrClosed } - err := p.waitTurn(ctx) - if err != nil { + if err := p.waitTurn(ctx); err != nil { return nil, err } @@ -477,6 +479,7 @@ func (p *ConnPool) ReapStaleConns() (int, error) { p.connsMu.Lock() cn := p.reapStaleConn() p.connsMu.Unlock() + p.freeTurn() if cn != nil { diff --git a/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go b/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go index c3e7e7c0458e..3adb99bc820f 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go +++ b/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go @@ -172,8 +172,7 @@ func (p *StickyConnPool) Reset(ctx context.Context) error { func (p *StickyConnPool) badConnError() error { if v := p._badConnError.Load(); v != nil { - err := v.(BadConnError) - if err.wrapped != nil { + if err := v.(BadConnError); err.wrapped != nil { return err } } diff --git a/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go b/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go index d9e6c1202638..10d1b4235b9f 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go +++ b/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go @@ -8,6 +8,7 @@ import ( "github.com/go-redis/redis/v8/internal/util" ) +// redis resp protocol data type. const ( ErrorReply = '-' StatusReply = '+' @@ -71,13 +72,25 @@ func (r *Reader) ReadLine() ([]byte, error) { func (r *Reader) readLine() ([]byte, error) { b, err := r.rd.ReadSlice('\n') if err != nil { - return nil, err + if err != bufio.ErrBufferFull { + return nil, err + } + + full := make([]byte, len(b)) + copy(full, b) + + b, err = r.rd.ReadBytes('\n') + if err != nil { + return nil, err + } + + full = append(full, b...) //nolint:makezero + b = full } if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' { return nil, fmt.Errorf("redis: invalid reply: %q", b) } - b = b[:len(b)-2] - return b, nil + return b[:len(b)-2], nil } func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) { diff --git a/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go b/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go index 8fa032317724..7d7183c32dae 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go +++ b/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go @@ -4,10 +4,12 @@ import ( "encoding" "fmt" "reflect" + "time" "github.com/go-redis/redis/v8/internal/util" ) +// Scan parses bytes `b` to `v` with appropriate type. func Scan(b []byte, v interface{}) error { switch v := v.(type) { case nil: @@ -99,6 +101,10 @@ func Scan(b []byte, v interface{}) error { case *bool: *v = len(b) == 1 && b[0] == '1' return nil + case *time.Time: + var err error + *v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b)) + return err case encoding.BinaryUnmarshaler: return v.UnmarshalBinary(b) default: @@ -124,7 +130,7 @@ func ScanSlice(data []string, slice interface{}) error { for i, s := range data { elem := next() if err := Scan([]byte(s), elem.Addr().Interface()); err != nil { - err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %s", i, s, err) + err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %w", i, s, err) return err } } diff --git a/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go b/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go index 40676f3cb667..2edccba94fe8 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go +++ b/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go @@ -43,3 +43,8 @@ func (s *source) Seed(seed int64) { s.src.Seed(seed) s.mu.Unlock() } + +// Shuffle pseudo-randomizes the order of elements. +// n is the number of elements. +// swap swaps the elements with indexes i and j. +func Shuffle(n int, swap func(i, j int)) { pseudo.Shuffle(n, swap) } diff --git a/vendor/github.com/go-redis/redis/v8/internal/util.go b/vendor/github.com/go-redis/redis/v8/internal/util.go index 9c861b0f4190..1a648fe63ccf 100644 --- a/vendor/github.com/go-redis/redis/v8/internal/util.go +++ b/vendor/github.com/go-redis/redis/v8/internal/util.go @@ -6,22 +6,23 @@ import ( "github.com/go-redis/redis/v8/internal/proto" "github.com/go-redis/redis/v8/internal/util" - "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/api/trace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" ) func Sleep(ctx context.Context, dur time.Duration) error { - return WithSpan(ctx, "sleep", func(ctx context.Context, span trace.Span) error { - t := time.NewTimer(dur) - defer t.Stop() + _, span := StartSpan(ctx, "time.Sleep") + defer span.End() - select { - case <-t.C: - return nil - case <-ctx.Done(): - return ctx.Err() - } - }) + t := time.NewTimer(dur) + defer t.Stop() + + select { + case <-t.C: + return nil + case <-ctx.Done(): + return ctx.Err() + } } func ToLower(s string) string { @@ -50,32 +51,20 @@ func isLower(s string) bool { return true } -func Unwrap(err error) error { - u, ok := err.(interface { - Unwrap() error - }) - if !ok { - return nil - } - return u.Unwrap() -} - //------------------------------------------------------------------------------ -func WithSpan(ctx context.Context, name string, fn func(context.Context, trace.Span) error) error { +var tracer = otel.Tracer("github.com/go-redis/redis") + +func StartSpan(ctx context.Context, name string) (context.Context, trace.Span) { if span := trace.SpanFromContext(ctx); !span.IsRecording() { - return fn(ctx, span) + return ctx, span } - - ctx, span := global.Tracer("github.com/go-redis/redis").Start(ctx, name) - defer span.End() - - return fn(ctx, span) + return tracer.Start(ctx, name) } -func RecordError(ctx context.Context, err error) error { +func RecordError(ctx context.Context, span trace.Span, err error) error { if err != proto.Nil { - trace.SpanFromContext(ctx).RecordError(ctx, err) + span.RecordError(err) } return err } diff --git a/vendor/github.com/go-redis/redis/v8/options.go b/vendor/github.com/go-redis/redis/v8/options.go index b3d3196a0681..0fd8e880af3c 100644 --- a/vendor/github.com/go-redis/redis/v8/options.go +++ b/vendor/github.com/go-redis/redis/v8/options.go @@ -14,8 +14,7 @@ import ( "github.com/go-redis/redis/v8/internal" "github.com/go-redis/redis/v8/internal/pool" - "go.opentelemetry.io/otel/api/trace" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" ) // Limiter is the interface of a rate limiter or a circuit breaker. @@ -58,7 +57,7 @@ type Options struct { DB int // Maximum number of retries before giving up. - // Default is 3 retries. + // Default is 3 retries; -1 (not 0) disables retries. MaxRetries int // Minimum backoff between each retry. // Default is 8 milliseconds; -1 disables backoff. @@ -271,7 +270,7 @@ func setupUnixConn(u *url.URL) (*Options, error) { db, err := strconv.Atoi(dbStr) if err != nil { - return nil, fmt.Errorf("redis: invalid database number: %s", err) + return nil, fmt.Errorf("redis: invalid database number: %w", err) } o.DB = db @@ -292,20 +291,21 @@ func getUserPassword(u *url.URL) (string, string) { func newConnPool(opt *Options) *pool.ConnPool { return pool.NewConnPool(&pool.Options{ Dialer: func(ctx context.Context) (net.Conn, error) { - var conn net.Conn - err := internal.WithSpan(ctx, "dialer", func(ctx context.Context, span trace.Span) error { - var err error + ctx, span := internal.StartSpan(ctx, "redis.dial") + defer span.End() + + if span.IsRecording() { span.SetAttributes( - label.String("redis.network", opt.Network), - label.String("redis.addr", opt.Addr), + attribute.String("db.connection_string", opt.Addr), ) - conn, err = opt.Dialer(ctx, opt.Network, opt.Addr) - if err != nil { - _ = internal.RecordError(ctx, err) - } - return err - }) - return conn, err + } + + cn, err := opt.Dialer(ctx, opt.Network, opt.Addr) + if err != nil { + return nil, internal.RecordError(ctx, span, err) + } + + return cn, nil }, PoolSize: opt.PoolSize, MinIdleConns: opt.MinIdleConns, diff --git a/vendor/github.com/go-redis/redis/v8/pubsub.go b/vendor/github.com/go-redis/redis/v8/pubsub.go index c56270b443e2..c6ffb256227c 100644 --- a/vendor/github.com/go-redis/redis/v8/pubsub.go +++ b/vendor/github.com/go-redis/redis/v8/pubsub.go @@ -2,7 +2,6 @@ package redis import ( "context" - "errors" "fmt" "strings" "sync" @@ -13,13 +12,6 @@ import ( "github.com/go-redis/redis/v8/internal/proto" ) -const ( - pingTimeout = time.Second - chanSendTimeout = time.Minute -) - -var errPingTimeout = errors.New("redis: ping timeout") - // PubSub implements Pub/Sub commands as described in // http://redis.io/topics/pubsub. Message receiving is NOT safe // for concurrent use by multiple goroutines. @@ -43,9 +35,12 @@ type PubSub struct { cmd *Cmd chOnce sync.Once - msgCh chan *Message - allCh chan interface{} - ping chan struct{} + msgCh *channel + allCh *channel +} + +func (c *PubSub) init() { + c.exit = make(chan struct{}) } func (c *PubSub) String() string { @@ -54,10 +49,6 @@ func (c *PubSub) String() string { return fmt.Sprintf("PubSub(%s)", strings.Join(channels, ", ")) } -func (c *PubSub) init() { - c.exit = make(chan struct{}) -} - func (c *PubSub) connWithLock(ctx context.Context) (*pool.Conn, error) { c.mu.Lock() cn, err := c.conn(ctx, nil) @@ -418,6 +409,15 @@ func (c *PubSub) ReceiveMessage(ctx context.Context) (*Message, error) { } } +func (c *PubSub) getContext() context.Context { + if c.cmd != nil { + return c.cmd.ctx + } + return context.Background() +} + +//------------------------------------------------------------------------------ + // Channel returns a Go channel for concurrently receiving messages. // The channel is closed together with the PubSub. If the Go channel // is blocked full for 30 seconds the message is dropped. @@ -425,26 +425,24 @@ func (c *PubSub) ReceiveMessage(ctx context.Context) (*Message, error) { // // go-redis periodically sends ping messages to test connection health // and re-subscribes if ping can not not received for 30 seconds. -func (c *PubSub) Channel() <-chan *Message { - return c.ChannelSize(100) -} - -// ChannelSize is like Channel, but creates a Go channel -// with specified buffer size. -func (c *PubSub) ChannelSize(size int) <-chan *Message { +func (c *PubSub) Channel(opts ...ChannelOption) <-chan *Message { c.chOnce.Do(func() { - c.initPing() - c.initMsgChan(size) + c.msgCh = newChannel(c, opts...) + c.msgCh.initMsgChan() }) if c.msgCh == nil { err := fmt.Errorf("redis: Channel can't be called after ChannelWithSubscriptions") panic(err) } - if cap(c.msgCh) != size { - err := fmt.Errorf("redis: PubSub.Channel size can not be changed once created") - panic(err) - } - return c.msgCh + return c.msgCh.msgCh +} + +// ChannelSize is like Channel, but creates a Go channel +// with specified buffer size. +// +// Deprecated: use Channel(WithChannelSize(size)), remove in v9. +func (c *PubSub) ChannelSize(size int) <-chan *Message { + return c.Channel(WithChannelSize(size)) } // ChannelWithSubscriptions is like Channel, but message type can be either @@ -452,59 +450,101 @@ func (c *PubSub) ChannelSize(size int) <-chan *Message { // reconnections. // // ChannelWithSubscriptions can not be used together with Channel or ChannelSize. -func (c *PubSub) ChannelWithSubscriptions(ctx context.Context, size int) <-chan interface{} { +func (c *PubSub) ChannelWithSubscriptions(_ context.Context, size int) <-chan interface{} { c.chOnce.Do(func() { - c.initPing() - c.initAllChan(size) + c.allCh = newChannel(c, WithChannelSize(size)) + c.allCh.initAllChan() }) if c.allCh == nil { err := fmt.Errorf("redis: ChannelWithSubscriptions can't be called after Channel") panic(err) } - if cap(c.allCh) != size { - err := fmt.Errorf("redis: PubSub.Channel size can not be changed once created") - panic(err) + return c.allCh.allCh +} + +type ChannelOption func(c *channel) + +// WithChannelSize specifies the Go chan size that is used to buffer incoming messages. +// +// The default is 100 messages. +func WithChannelSize(size int) ChannelOption { + return func(c *channel) { + c.chanSize = size } - return c.allCh } -func (c *PubSub) getContext() context.Context { - if c.cmd != nil { - return c.cmd.ctx +// WithChannelHealthCheckInterval specifies the health check interval. +// PubSub will ping Redis Server if it does not receive any messages within the interval. +// To disable health check, use zero interval. +// +// The default is 3 seconds. +func WithChannelHealthCheckInterval(d time.Duration) ChannelOption { + return func(c *channel) { + c.checkInterval = d } - return context.Background() } -func (c *PubSub) initPing() { +// WithChannelSendTimeout specifies the channel send timeout after which +// the message is dropped. +// +// The default is 60 seconds. +func WithChannelSendTimeout(d time.Duration) ChannelOption { + return func(c *channel) { + c.chanSendTimeout = d + } +} + +type channel struct { + pubSub *PubSub + + msgCh chan *Message + allCh chan interface{} + ping chan struct{} + + chanSize int + chanSendTimeout time.Duration + checkInterval time.Duration +} + +func newChannel(pubSub *PubSub, opts ...ChannelOption) *channel { + c := &channel{ + pubSub: pubSub, + + chanSize: 100, + chanSendTimeout: time.Minute, + checkInterval: 3 * time.Second, + } + for _, opt := range opts { + opt(c) + } + if c.checkInterval > 0 { + c.initHealthCheck() + } + return c +} + +func (c *channel) initHealthCheck() { ctx := context.TODO() c.ping = make(chan struct{}, 1) + go func() { timer := time.NewTimer(time.Minute) timer.Stop() - healthy := true for { - timer.Reset(pingTimeout) + timer.Reset(c.checkInterval) select { case <-c.ping: - healthy = true if !timer.Stop() { <-timer.C } case <-timer.C: - pingErr := c.Ping(ctx) - if healthy { - healthy = false - } else { - if pingErr == nil { - pingErr = errPingTimeout - } - c.mu.Lock() - c.reconnect(ctx, pingErr) - healthy = true - c.mu.Unlock() + if pingErr := c.pubSub.Ping(ctx); pingErr != nil { + c.pubSub.mu.Lock() + c.pubSub.reconnect(ctx, pingErr) + c.pubSub.mu.Unlock() } - case <-c.exit: + case <-c.pubSub.exit: return } } @@ -512,16 +552,17 @@ func (c *PubSub) initPing() { } // initMsgChan must be in sync with initAllChan. -func (c *PubSub) initMsgChan(size int) { +func (c *channel) initMsgChan() { ctx := context.TODO() - c.msgCh = make(chan *Message, size) + c.msgCh = make(chan *Message, c.chanSize) + go func() { timer := time.NewTimer(time.Minute) timer.Stop() var errCount int for { - msg, err := c.Receive(ctx) + msg, err := c.pubSub.Receive(ctx) if err != nil { if err == pool.ErrClosed { close(c.msgCh) @@ -548,7 +589,7 @@ func (c *PubSub) initMsgChan(size int) { case *Pong: // Ignore. case *Message: - timer.Reset(chanSendTimeout) + timer.Reset(c.chanSendTimeout) select { case c.msgCh <- msg: if !timer.Stop() { @@ -556,30 +597,28 @@ func (c *PubSub) initMsgChan(size int) { } case <-timer.C: internal.Logger.Printf( - c.getContext(), - "redis: %s channel is full for %s (message is dropped)", - c, - chanSendTimeout, - ) + ctx, "redis: %s channel is full for %s (message is dropped)", + c, c.chanSendTimeout) } default: - internal.Logger.Printf(c.getContext(), "redis: unknown message type: %T", msg) + internal.Logger.Printf(ctx, "redis: unknown message type: %T", msg) } } }() } // initAllChan must be in sync with initMsgChan. -func (c *PubSub) initAllChan(size int) { +func (c *channel) initAllChan() { ctx := context.TODO() - c.allCh = make(chan interface{}, size) + c.allCh = make(chan interface{}, c.chanSize) + go func() { - timer := time.NewTimer(pingTimeout) + timer := time.NewTimer(time.Minute) timer.Stop() var errCount int for { - msg, err := c.Receive(ctx) + msg, err := c.pubSub.Receive(ctx) if err != nil { if err == pool.ErrClosed { close(c.allCh) @@ -601,29 +640,23 @@ func (c *PubSub) initAllChan(size int) { } switch msg := msg.(type) { - case *Subscription: - c.sendMessage(msg, timer) case *Pong: // Ignore. - case *Message: - c.sendMessage(msg, timer) + case *Subscription, *Message: + timer.Reset(c.chanSendTimeout) + select { + case c.allCh <- msg: + if !timer.Stop() { + <-timer.C + } + case <-timer.C: + internal.Logger.Printf( + ctx, "redis: %s channel is full for %s (message is dropped)", + c, c.chanSendTimeout) + } default: - internal.Logger.Printf(c.getContext(), "redis: unknown message type: %T", msg) + internal.Logger.Printf(ctx, "redis: unknown message type: %T", msg) } } }() } - -func (c *PubSub) sendMessage(msg interface{}, timer *time.Timer) { - timer.Reset(pingTimeout) - select { - case c.allCh <- msg: - if !timer.Stop() { - <-timer.C - } - case <-timer.C: - internal.Logger.Printf( - c.getContext(), - "redis: %s channel is full for %s (message is dropped)", c, pingTimeout) - } -} diff --git a/vendor/github.com/go-redis/redis/v8/redis.go b/vendor/github.com/go-redis/redis/v8/redis.go index b70fef3191d5..7995c43657be 100644 --- a/vendor/github.com/go-redis/redis/v8/redis.go +++ b/vendor/github.com/go-redis/redis/v8/redis.go @@ -2,14 +2,15 @@ package redis import ( "context" + "errors" "fmt" + "sync/atomic" "time" "github.com/go-redis/redis/v8/internal" "github.com/go-redis/redis/v8/internal/pool" "github.com/go-redis/redis/v8/internal/proto" - "go.opentelemetry.io/otel/api/trace" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" ) // Nil reply returned by Redis when key does not exist. @@ -129,20 +130,7 @@ func (hs hooks) processTxPipeline( } func (hs hooks) withContext(ctx context.Context, fn func() error) error { - done := ctx.Done() - if done == nil { - return fn() - } - - errc := make(chan error, 1) - go func() { errc <- fn() }() - - select { - case <-done: - return ctx.Err() - case err := <-errc: - return err - } + return fn() } //------------------------------------------------------------------------------ @@ -225,12 +213,9 @@ func (c *baseClient) _getConn(ctx context.Context) (*pool.Conn, error) { return cn, nil } - err = internal.WithSpan(ctx, "init_conn", func(ctx context.Context, span trace.Span) error { - return c.initConn(ctx, cn) - }) - if err != nil { + if err := c.initConn(ctx, cn); err != nil { c.connPool.Remove(ctx, cn, err) - if err := internal.Unwrap(err); err != nil { + if err := errors.Unwrap(err); err != nil { return nil, err } return nil, err @@ -252,6 +237,9 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error { return nil } + ctx, span := internal.StartSpan(ctx, "redis.init_conn") + defer span.End() + connPool := pool.NewSingleConnPool(c.connPool, cn) conn := newConn(ctx, c.opt, connPool) @@ -299,25 +287,45 @@ func (c *baseClient) releaseConn(ctx context.Context, cn *pool.Conn, err error) func (c *baseClient) withConn( ctx context.Context, fn func(context.Context, *pool.Conn) error, ) error { - return internal.WithSpan(ctx, "with_conn", func(ctx context.Context, span trace.Span) error { - cn, err := c.getConn(ctx) - if err != nil { - return err - } + ctx, span := internal.StartSpan(ctx, "redis.with_conn") + defer span.End() - if span.IsRecording() { - if remoteAddr := cn.RemoteAddr(); remoteAddr != nil { - span.SetAttributes(label.String("net.peer.ip", remoteAddr.String())) - } + cn, err := c.getConn(ctx) + if err != nil { + return err + } + + if span.IsRecording() { + if remoteAddr := cn.RemoteAddr(); remoteAddr != nil { + span.SetAttributes(attribute.String("net.peer.ip", remoteAddr.String())) } + } - defer func() { - c.releaseConn(ctx, cn, err) - }() + defer func() { + c.releaseConn(ctx, cn, err) + }() + done := ctx.Done() //nolint:ifshort + + if done == nil { err = fn(ctx, cn) return err - }) + } + + errc := make(chan error, 1) + go func() { errc <- fn(ctx, cn) }() + + select { + case <-done: + _ = cn.Close() + // Wait for the goroutine to finish and send something. + <-errc + + err = ctx.Err() + return err + case err = <-errc: + return err + } } func (c *baseClient) process(ctx context.Context, cmd Cmder) error { @@ -325,45 +333,50 @@ func (c *baseClient) process(ctx context.Context, cmd Cmder) error { for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ { attempt := attempt - var retry bool - err := internal.WithSpan(ctx, "process", func(ctx context.Context, span trace.Span) error { - if attempt > 0 { - if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { - return err - } - } - - retryTimeout := true - err := c.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { - err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error { - return writeCmd(wr, cmd) - }) - if err != nil { - return err - } - - err = cn.WithReader(ctx, c.cmdTimeout(cmd), cmd.readReply) - if err != nil { - retryTimeout = cmd.readTimeout() == nil - return err - } - - return nil - }) - if err == nil { - return nil - } - retry = shouldRetry(err, retryTimeout) - return err - }) + retry, err := c._process(ctx, cmd, attempt) if err == nil || !retry { return err } + lastErr = err } return lastErr } +func (c *baseClient) _process(ctx context.Context, cmd Cmder, attempt int) (bool, error) { + if attempt > 0 { + if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { + return false, err + } + } + + retryTimeout := uint32(1) + err := c.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { + err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error { + return writeCmd(wr, cmd) + }) + if err != nil { + return err + } + + err = cn.WithReader(ctx, c.cmdTimeout(cmd), cmd.readReply) + if err != nil { + if cmd.readTimeout() == nil { + atomic.StoreUint32(&retryTimeout, 1) + } + return err + } + + return nil + }) + if err == nil { + return false, nil + } + + retry := shouldRetry(err, atomic.LoadUint32(&retryTimeout) == 1) + return retry, err +} + func (c *baseClient) retryBackoff(attempt int) time.Duration { return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff) } @@ -719,6 +732,7 @@ type conn struct { baseClient cmdable statefulCmdable + hooks // TODO: inherit hooks } // Conn is like Client, but its pool contains single connection. @@ -743,7 +757,15 @@ func newConn(ctx context.Context, opt *Options, connPool pool.Pooler) *Conn { } func (c *Conn) Process(ctx context.Context, cmd Cmder) error { - return c.baseClient.process(ctx, cmd) + return c.hooks.process(ctx, cmd, c.baseClient.process) +} + +func (c *Conn) processPipeline(ctx context.Context, cmds []Cmder) error { + return c.hooks.processPipeline(ctx, cmds, c.baseClient.processPipeline) +} + +func (c *Conn) processTxPipeline(ctx context.Context, cmds []Cmder) error { + return c.hooks.processTxPipeline(ctx, cmds, c.baseClient.processTxPipeline) } func (c *Conn) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { diff --git a/vendor/github.com/go-redis/redis/v8/renovate.json b/vendor/github.com/go-redis/redis/v8/renovate.json deleted file mode 100644 index f45d8f110c30..000000000000 --- a/vendor/github.com/go-redis/redis/v8/renovate.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "config:base" - ] -} diff --git a/vendor/github.com/go-redis/redis/v8/ring.go b/vendor/github.com/go-redis/redis/v8/ring.go index 205b0249d784..34d05f35aeeb 100644 --- a/vendor/github.com/go-redis/redis/v8/ring.go +++ b/vendor/github.com/go-redis/redis/v8/ring.go @@ -13,7 +13,6 @@ import ( "github.com/cespare/xxhash/v2" "github.com/dgryski/go-rendezvous" - "github.com/go-redis/redis/v8/internal" "github.com/go-redis/redis/v8/internal/hashtag" "github.com/go-redis/redis/v8/internal/pool" diff --git a/vendor/github.com/go-redis/redis/v8/script.go b/vendor/github.com/go-redis/redis/v8/script.go index 07ed482c57ce..5cab18d617c8 100644 --- a/vendor/github.com/go-redis/redis/v8/script.go +++ b/vendor/github.com/go-redis/redis/v8/script.go @@ -8,7 +8,7 @@ import ( "strings" ) -type scripter interface { +type Scripter interface { Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd @@ -16,9 +16,9 @@ type scripter interface { } var ( - _ scripter = (*Client)(nil) - _ scripter = (*Ring)(nil) - _ scripter = (*ClusterClient)(nil) + _ Scripter = (*Client)(nil) + _ Scripter = (*Ring)(nil) + _ Scripter = (*ClusterClient)(nil) ) type Script struct { @@ -38,25 +38,25 @@ func (s *Script) Hash() string { return s.hash } -func (s *Script) Load(ctx context.Context, c scripter) *StringCmd { +func (s *Script) Load(ctx context.Context, c Scripter) *StringCmd { return c.ScriptLoad(ctx, s.src) } -func (s *Script) Exists(ctx context.Context, c scripter) *BoolSliceCmd { +func (s *Script) Exists(ctx context.Context, c Scripter) *BoolSliceCmd { return c.ScriptExists(ctx, s.hash) } -func (s *Script) Eval(ctx context.Context, c scripter, keys []string, args ...interface{}) *Cmd { +func (s *Script) Eval(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd { return c.Eval(ctx, s.src, keys, args...) } -func (s *Script) EvalSha(ctx context.Context, c scripter, keys []string, args ...interface{}) *Cmd { +func (s *Script) EvalSha(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd { return c.EvalSha(ctx, s.hash, keys, args...) } // Run optimistically uses EVALSHA to run the script. If script does not exist // it is retried using EVAL. -func (s *Script) Run(ctx context.Context, c scripter, keys []string, args ...interface{}) *Cmd { +func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd { r := s.EvalSha(ctx, c, keys, args...) if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") { return s.Eval(ctx, c, keys, args...) diff --git a/vendor/github.com/go-redis/redis/v8/sentinel.go b/vendor/github.com/go-redis/redis/v8/sentinel.go index 7db984373f93..ca2e088a7624 100644 --- a/vendor/github.com/go-redis/redis/v8/sentinel.go +++ b/vendor/github.com/go-redis/redis/v8/sentinel.go @@ -36,6 +36,10 @@ type FailoverOptions struct { // Route all commands to slave read-only nodes. SlaveOnly bool + // Use slaves disconnected with master when cannot get connected slaves + // Now, this option only works in RandomSlaveAddr function. + UseDisconnectedSlaves bool + // Following options are copied from Options struct. Dialer func(ctx context.Context, network, addr string) (net.Conn, error) @@ -167,6 +171,10 @@ func NewFailoverClient(failoverOpt *FailoverOptions) *Client { sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs)) copy(sentinelAddrs, failoverOpt.SentinelAddrs) + rand.Shuffle(len(sentinelAddrs), func(i, j int) { + sentinelAddrs[i], sentinelAddrs[j] = sentinelAddrs[j], sentinelAddrs[i] + }) + failover := &sentinelFailover{ opt: failoverOpt, sentinelAddrs: sentinelAddrs, @@ -177,11 +185,14 @@ func NewFailoverClient(failoverOpt *FailoverOptions) *Client { opt.init() connPool := newConnPool(opt) + + failover.mu.Lock() failover.onFailover = func(ctx context.Context, addr string) { _ = connPool.Filter(func(cn *pool.Conn) bool { return cn.RemoteAddr().String() != addr }) } + failover.mu.Unlock() c := Client{ baseClient: newBaseClient(opt, connPool), @@ -208,14 +219,21 @@ func masterSlaveDialer( failover.trySwitchMaster(ctx, addr) } } - if err != nil { return nil, err } if failover.opt.Dialer != nil { return failover.opt.Dialer(ctx, network, addr) } - return net.DialTimeout("tcp", addr, failover.opt.DialTimeout) + + netDialer := &net.Dialer{ + Timeout: failover.opt.DialTimeout, + KeepAlive: 5 * time.Minute, + } + if failover.opt.TLSConfig == nil { + return netDialer.DialContext(ctx, network, addr) + } + return tls.DialWithDialer(netDialer, network, addr, failover.opt.TLSConfig) } } @@ -430,10 +448,22 @@ func (c *sentinelFailover) closeSentinel() error { } func (c *sentinelFailover) RandomSlaveAddr(ctx context.Context) (string, error) { - addresses, err := c.slaveAddrs(ctx) + if c.opt == nil { + return "", errors.New("opt is nil") + } + + addresses, err := c.slaveAddrs(ctx, false) if err != nil { return "", err } + + if len(addresses) == 0 && c.opt.UseDisconnectedSlaves { + addresses, err = c.slaveAddrs(ctx, true) + if err != nil { + return "", err + } + } + if len(addresses) == 0 { return c.MasterAddr(ctx) } @@ -482,10 +512,10 @@ func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) { return addr, nil } - return "", errors.New("redis: all sentinels are unreachable") + return "", errors.New("redis: all sentinels specified in configuration are unreachable") } -func (c *sentinelFailover) slaveAddrs(ctx context.Context) ([]string, error) { +func (c *sentinelFailover) slaveAddrs(ctx context.Context, useDisconnected bool) ([]string, error) { c.mu.RLock() sentinel := c.sentinel c.mu.RUnlock() @@ -508,6 +538,8 @@ func (c *sentinelFailover) slaveAddrs(ctx context.Context) ([]string, error) { _ = c.closeSentinel() } + var sentinelReachable bool + for i, sentinelAddr := range c.sentinelAddrs { sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr)) @@ -518,16 +550,22 @@ func (c *sentinelFailover) slaveAddrs(ctx context.Context) ([]string, error) { _ = sentinel.Close() continue } - + sentinelReachable = true + addrs := parseSlaveAddrs(slaves, useDisconnected) + if len(addrs) == 0 { + continue + } // Push working sentinel to the top. c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0] c.setSentinel(ctx, sentinel) - addrs := parseSlaveAddrs(slaves) return addrs, nil } - return []string{}, errors.New("redis: all sentinels are unreachable") + if sentinelReachable { + return []string{}, nil + } + return []string{}, errors.New("redis: all sentinels specified in configuration are unreachable") } func (c *sentinelFailover) getMasterAddr(ctx context.Context, sentinel *SentinelClient) string { @@ -547,12 +585,11 @@ func (c *sentinelFailover) getSlaveAddrs(ctx context.Context, sentinel *Sentinel c.opt.MasterName, err) return []string{} } - return parseSlaveAddrs(addrs) + return parseSlaveAddrs(addrs, false) } -func parseSlaveAddrs(addrs []interface{}) []string { +func parseSlaveAddrs(addrs []interface{}, keepDisconnected bool) []string { nodes := make([]string, 0, len(addrs)) - for _, node := range addrs { ip := "" port := "" @@ -574,8 +611,12 @@ func parseSlaveAddrs(addrs []interface{}) []string { for _, flag := range flags { switch flag { - case "s_down", "o_down", "disconnected": + case "s_down", "o_down": isDown = true + case "disconnected": + if !keepDisconnected { + isDown = true + } } } @@ -589,7 +630,7 @@ func parseSlaveAddrs(addrs []interface{}) []string { func (c *sentinelFailover) trySwitchMaster(ctx context.Context, addr string) { c.mu.RLock() - currentAddr := c._masterAddr + currentAddr := c._masterAddr //nolint:ifshort c.mu.RUnlock() if addr == currentAddr { @@ -630,15 +671,22 @@ func (c *sentinelFailover) discoverSentinels(ctx context.Context) { } for _, sentinel := range sentinels { vals := sentinel.([]interface{}) + var ip, port string for i := 0; i < len(vals); i += 2 { key := vals[i].(string) - if key == "name" { - sentinelAddr := vals[i+1].(string) - if !contains(c.sentinelAddrs, sentinelAddr) { - internal.Logger.Printf(ctx, "sentinel: discovered new sentinel=%q for master=%q", - sentinelAddr, c.opt.MasterName) - c.sentinelAddrs = append(c.sentinelAddrs, sentinelAddr) - } + switch key { + case "ip": + ip = vals[i+1].(string) + case "port": + port = vals[i+1].(string) + } + } + if ip != "" && port != "" { + sentinelAddr := net.JoinHostPort(ip, port) + if !contains(c.sentinelAddrs, sentinelAddr) { + internal.Logger.Printf(ctx, "sentinel: discovered new sentinel=%q for master=%q", + sentinelAddr, c.opt.MasterName) + c.sentinelAddrs = append(c.sentinelAddrs, sentinelAddr) } } } @@ -646,6 +694,7 @@ func (c *sentinelFailover) discoverSentinels(ctx context.Context) { func (c *sentinelFailover) listen(pubsub *PubSub) { ctx := context.TODO() + if c.onUpdate != nil { c.onUpdate(ctx) } @@ -701,7 +750,7 @@ func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient { Addr: masterAddr, }} - slaveAddrs, err := failover.slaveAddrs(ctx) + slaveAddrs, err := failover.slaveAddrs(ctx, false) if err != nil { return nil, err } @@ -723,9 +772,12 @@ func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient { } c := NewClusterClient(opt) + + failover.mu.Lock() failover.onUpdate = func(ctx context.Context) { c.ReloadState(ctx) } + failover.mu.Unlock() return c } diff --git a/vendor/github.com/go-redis/redis/v8/tx.go b/vendor/github.com/go-redis/redis/v8/tx.go index ad825c610cac..08d381a9d3c4 100644 --- a/vendor/github.com/go-redis/redis/v8/tx.go +++ b/vendor/github.com/go-redis/redis/v8/tx.go @@ -65,16 +65,13 @@ func (c *Tx) Process(ctx context.Context, cmd Cmder) error { // The transaction is automatically closed when fn exits. func (c *Client) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error { tx := c.newTx(ctx) + defer tx.Close(ctx) if len(keys) > 0 { if err := tx.Watch(ctx, keys...).Err(); err != nil { - _ = tx.Close(ctx) return err } } - - err := fn(tx) - _ = tx.Close(ctx) - return err + return fn(tx) } // Close closes the transaction, releasing any open resources. diff --git a/vendor/github.com/go-redis/redis/v8/universal.go b/vendor/github.com/go-redis/redis/v8/universal.go index 5a7d0d5bc404..bb5f8b61636d 100644 --- a/vendor/github.com/go-redis/redis/v8/universal.go +++ b/vendor/github.com/go-redis/redis/v8/universal.go @@ -53,6 +53,7 @@ type UniversalOptions struct { // The sentinel master name. // Only failover clients. + MasterName string } @@ -168,9 +169,9 @@ func (o *UniversalOptions) Simple() *Options { // -------------------------------------------------------------------- // UniversalClient is an abstract client which - based on the provided options - -// can connect to either clusters, or sentinel-backed failover instances -// or simple single-instance servers. This can be useful for testing -// cluster-specific applications locally. +// represents either a ClusterClient, a FailoverClient, or a single-node Client. +// This can be useful for testing cluster-specific applications locally or having different +// clients in different environments. type UniversalClient interface { Cmdable Context() context.Context @@ -181,6 +182,7 @@ type UniversalClient interface { Subscribe(ctx context.Context, channels ...string) *PubSub PSubscribe(ctx context.Context, channels ...string) *PubSub Close() error + PoolStats() *PoolStats } var ( @@ -189,12 +191,12 @@ var ( _ UniversalClient = (*Ring)(nil) ) -// NewUniversalClient returns a new multi client. The type of client returned depends -// on the following three conditions: +// NewUniversalClient returns a new multi client. The type of the returned client depends +// on the following conditions: // -// 1. if a MasterName is passed a sentinel-backed FailoverClient will be returned -// 2. if the number of Addrs is two or more, a ClusterClient will be returned -// 3. otherwise, a single-node redis Client will be returned. +// 1. If the MasterName option is specified, a sentinel-backed FailoverClient is returned. +// 2. if the number of Addrs is two or more, a ClusterClient is returned. +// 3. Otherwise, a single-node Client is returned. func NewUniversalClient(opts *UniversalOptions) UniversalClient { if opts.MasterName != "" { return NewFailoverClient(opts.Failover()) diff --git a/vendor/github.com/hashicorp/memberlist/event_delegate.go b/vendor/github.com/hashicorp/memberlist/event_delegate.go index 35e2a56fdd06..352f98b43e70 100644 --- a/vendor/github.com/hashicorp/memberlist/event_delegate.go +++ b/vendor/github.com/hashicorp/memberlist/event_delegate.go @@ -49,13 +49,16 @@ type NodeEvent struct { } func (c *ChannelEventDelegate) NotifyJoin(n *Node) { - c.Ch <- NodeEvent{NodeJoin, n} + node := *n + c.Ch <- NodeEvent{NodeJoin, &node} } func (c *ChannelEventDelegate) NotifyLeave(n *Node) { - c.Ch <- NodeEvent{NodeLeave, n} + node := *n + c.Ch <- NodeEvent{NodeLeave, &node} } func (c *ChannelEventDelegate) NotifyUpdate(n *Node) { - c.Ch <- NodeEvent{NodeUpdate, n} + node := *n + c.Ch <- NodeEvent{NodeUpdate, &node} } diff --git a/vendor/github.com/hashicorp/memberlist/state.go b/vendor/github.com/hashicorp/memberlist/state.go index 7044f293c9d2..5e4f7fdd704c 100644 --- a/vendor/github.com/hashicorp/memberlist/state.go +++ b/vendor/github.com/hashicorp/memberlist/state.go @@ -602,13 +602,13 @@ func (m *Memberlist) gossip() { addr := node.Address() if len(msgs) == 1 { // Send single message as is - if err := m.rawSendMsgPacket(node.FullAddress(), &node.Node, msgs[0]); err != nil { + if err := m.rawSendMsgPacket(node.FullAddress(), &node, msgs[0]); err != nil { m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err) } } else { // Otherwise create and send a compound message compound := makeCompoundMessage(msgs) - if err := m.rawSendMsgPacket(node.FullAddress(), &node.Node, compound.Bytes()); err != nil { + if err := m.rawSendMsgPacket(node.FullAddress(), &node, compound.Bytes()); err != nil { m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err) } } @@ -1198,9 +1198,14 @@ func (m *Memberlist) suspectNode(s *suspect) { min := suspicionTimeout(m.config.SuspicionMult, n, m.config.ProbeInterval) max := time.Duration(m.config.SuspicionMaxTimeoutMult) * min fn := func(numConfirmations int) { + var d *dead + m.nodeLock.Lock() state, ok := m.nodeMap[s.Node] timeout := ok && state.State == StateSuspect && state.StateChange == changeTime + if timeout { + d = &dead{Incarnation: state.Incarnation, Node: state.Name, From: m.config.Name} + } m.nodeLock.Unlock() if timeout { @@ -1210,8 +1215,8 @@ func (m *Memberlist) suspectNode(s *suspect) { m.logger.Printf("[INFO] memberlist: Marking %s as failed, suspect timeout reached (%d peer confirmations)", state.Name, numConfirmations) - d := dead{Incarnation: state.Incarnation, Node: state.Name, From: m.config.Name} - m.deadNode(&d) + + m.deadNode(d) } } m.nodeTimers[s.Node] = newSuspicion(s.From, k, min, max, fn) diff --git a/vendor/github.com/hashicorp/memberlist/util.go b/vendor/github.com/hashicorp/memberlist/util.go index 22bf6b440b39..7ca52c4cd16e 100644 --- a/vendor/github.com/hashicorp/memberlist/util.go +++ b/vendor/github.com/hashicorp/memberlist/util.go @@ -119,35 +119,35 @@ func moveDeadNodes(nodes []*nodeState, gossipToTheDeadTime time.Duration) int { return n - numDead } -// kRandomNodes is used to select up to k random nodes, excluding any nodes where -// the filter function returns true. It is possible that less than k nodes are +// kRandomNodes is used to select up to k random Nodes, excluding any nodes where +// the exclude function returns true. It is possible that less than k nodes are // returned. -func kRandomNodes(k int, nodes []*nodeState, filterFn func(*nodeState) bool) []*nodeState { +func kRandomNodes(k int, nodes []*nodeState, exclude func(*nodeState) bool) []Node { n := len(nodes) - kNodes := make([]*nodeState, 0, k) + kNodes := make([]Node, 0, k) OUTER: // Probe up to 3*n times, with large n this is not necessary // since k << n, but with small n we want search to be // exhaustive for i := 0; i < 3*n && len(kNodes) < k; i++ { - // Get random node + // Get random nodeState idx := randomOffset(n) - node := nodes[idx] + state := nodes[idx] // Give the filter a shot at it. - if filterFn != nil && filterFn(node) { + if exclude != nil && exclude(state) { continue OUTER } // Check if we have this node already for j := 0; j < len(kNodes); j++ { - if node == kNodes[j] { + if state.Node.Name == kNodes[j].Name { continue OUTER } } // Append the node - kNodes = append(kNodes, node) + kNodes = append(kNodes, state.Node) } return kNodes } diff --git a/vendor/github.com/jessevdk/go-flags/.travis.yml b/vendor/github.com/jessevdk/go-flags/.travis.yml index 0f0728d2fd32..2fc5e5f5b57d 100644 --- a/vendor/github.com/jessevdk/go-flags/.travis.yml +++ b/vendor/github.com/jessevdk/go-flags/.travis.yml @@ -5,19 +5,14 @@ os: - osx go: - - 1.x - - 1.7.x - - 1.8.x - - 1.9.x - - 1.10.x + - 1.16.x install: # go-flags - - go get -d -v ./... - go build -v ./... # linting - - go get github.com/golang/lint/golint + - go get -v golang.org/x/lint/golint # code coverage - go get golang.org/x/tools/cmd/cover diff --git a/vendor/github.com/jessevdk/go-flags/README.md b/vendor/github.com/jessevdk/go-flags/README.md index 3b02394ed9cb..f22650b20ad4 100644 --- a/vendor/github.com/jessevdk/go-flags/README.md +++ b/vendor/github.com/jessevdk/go-flags/README.md @@ -61,6 +61,9 @@ var opts struct { // Example of a required flag Name string `short:"n" long:"name" description:"A name" required:"true"` + // Example of a flag restricted to a pre-defined set of strings + Animal string `long:"animal" choice:"cat" choice:"dog"` + // Example of a value name File string `short:"f" long:"file" description:"A file" value-name:"FILE"` @@ -91,6 +94,7 @@ args := []string{ "-vv", "--offset=5", "-n", "Me", + "--animal", "dog", // anything other than "cat" or "dog" will raise an error "-p", "3", "-s", "hello", "-s", "world", @@ -115,6 +119,7 @@ if err != nil { fmt.Printf("Verbosity: %v\n", opts.Verbose) fmt.Printf("Offset: %d\n", opts.Offset) fmt.Printf("Name: %s\n", opts.Name) +fmt.Printf("Animal: %s\n", opts.Animal) fmt.Printf("Ptr: %d\n", *opts.Ptr) fmt.Printf("StringSlice: %v\n", opts.StringSlice) fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) diff --git a/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh b/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh index c494f6119d3e..5edc430ed920 100644 --- a/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh +++ b/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh @@ -14,3 +14,7 @@ echo '# darwin' GOARCH=amd64 GOOS=darwin go build echo '# freebsd' GOARCH=amd64 GOOS=freebsd go build +echo '# aix ppc64' +GOARCH=ppc64 GOOS=aix go build +echo '# solaris amd64' +GOARCH=amd64 GOOS=solaris go build diff --git a/vendor/github.com/jessevdk/go-flags/command.go b/vendor/github.com/jessevdk/go-flags/command.go index 486bacba1ffe..879465d7a501 100644 --- a/vendor/github.com/jessevdk/go-flags/command.go +++ b/vendor/github.com/jessevdk/go-flags/command.go @@ -438,7 +438,7 @@ func (c *Command) match(name string) bool { return false } -func (c *Command) hasCliOptions() bool { +func (c *Command) hasHelpOptions() bool { ret := false c.eachGroup(func(g *Group) { @@ -447,7 +447,7 @@ func (c *Command) hasCliOptions() bool { } for _, opt := range g.options { - if opt.canCli() { + if opt.showInHelp() { ret = true } } diff --git a/vendor/github.com/jessevdk/go-flags/completion.go b/vendor/github.com/jessevdk/go-flags/completion.go index 7a7a08b93867..8ed61f1db66e 100644 --- a/vendor/github.com/jessevdk/go-flags/completion.go +++ b/vendor/github.com/jessevdk/go-flags/completion.go @@ -2,6 +2,7 @@ package flags import ( "fmt" + "os" "path/filepath" "reflect" "sort" @@ -62,6 +63,11 @@ func completionsWithoutDescriptions(items []string) []Completion { // prefix. func (f *Filename) Complete(match string) []Completion { ret, _ := filepath.Glob(match + "*") + if len(ret) == 1 { + if info, err := os.Stat(ret[0]); err == nil && info.IsDir() { + ret[0] = ret[0] + "/" + } + } return completionsWithoutDescriptions(ret) } @@ -76,7 +82,7 @@ func (c *completion) skipPositional(s *parseState, n int) { func (c *completion) completeOptionNames(s *parseState, prefix string, match string, short bool) []Completion { if short && len(match) != 0 { return []Completion{ - Completion{ + { Item: prefix + match, }, } @@ -124,7 +130,7 @@ func (c *completion) completeCommands(s *parseState, match string) []Completion n := make([]Completion, 0, len(s.command.commands)) for _, cmd := range s.command.commands { - if cmd.data != c && strings.HasPrefix(cmd.Name, match) { + if cmd.data != c && !cmd.Hidden && strings.HasPrefix(cmd.Name, match) { n = append(n, Completion{ Item: cmd.Name, Description: cmd.ShortDescription, diff --git a/vendor/github.com/jessevdk/go-flags/convert.go b/vendor/github.com/jessevdk/go-flags/convert.go index 984aac89cc0a..cda29b2f04b7 100644 --- a/vendor/github.com/jessevdk/go-flags/convert.go +++ b/vendor/github.com/jessevdk/go-flags/convert.go @@ -28,6 +28,15 @@ type Unmarshaler interface { UnmarshalFlag(value string) error } +// ValueValidator is the interface implemented by types that can validate a +// flag argument themselves. The provided value is directly passed from the +// command line. +type ValueValidator interface { + // IsValidValue returns an error if the provided string value is valid for + // the flag. + IsValidValue(value string) error +} + func getBase(options multiTag, base int) (int, error) { sbase := options.Get("base") diff --git a/vendor/github.com/jessevdk/go-flags/error.go b/vendor/github.com/jessevdk/go-flags/error.go index 05528d8d2847..73e07cfc2968 100644 --- a/vendor/github.com/jessevdk/go-flags/error.go +++ b/vendor/github.com/jessevdk/go-flags/error.go @@ -97,6 +97,10 @@ func (e ErrorType) String() string { return "unrecognized error type" } +func (e ErrorType) Error() string { + return e.String() +} + // Error represents a parser error. The error returned from Parse is of this // type. The error contains both a Type and Message. type Error struct { diff --git a/vendor/github.com/jessevdk/go-flags/flags.go b/vendor/github.com/jessevdk/go-flags/flags.go index 889762d1029d..ac2157dd6049 100644 --- a/vendor/github.com/jessevdk/go-flags/flags.go +++ b/vendor/github.com/jessevdk/go-flags/flags.go @@ -109,7 +109,8 @@ The following is a list of tags for struct fields supported by go-flags: value-name: the name of the argument value (to be shown in the help) (optional) choice: limits the values for an option to a set of values. - This tag can be specified multiple times (optional) + Repeat this tag once for each allowable value. + e.g. `long:"animal" choice:"cat" choice:"dog"` hidden: if non-empty, the option is not visible in the help or man page. base: a base (radix) used to convert strings to integer values, the @@ -125,6 +126,10 @@ The following is a list of tags for struct fields supported by go-flags: gets prepended to every option's long name and subgroup's namespace of this group, separated by the parser's namespace delimiter (optional) + env-namespace: when specified on a group struct field, the env-namespace + gets prepended to every option's env key and + subgroup's env-namespace of this group, separated by + the parser's env-namespace delimiter (optional) command: when specified on a struct field, makes the struct field a (sub)command with the given name (optional) subcommands-optional: when specified on a command struct field, makes diff --git a/vendor/github.com/jessevdk/go-flags/go.mod b/vendor/github.com/jessevdk/go-flags/go.mod new file mode 100644 index 000000000000..a626c5d108e5 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/go.mod @@ -0,0 +1,5 @@ +module github.com/jessevdk/go-flags + +go 1.15 + +require golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 diff --git a/vendor/github.com/jessevdk/go-flags/go.sum b/vendor/github.com/jessevdk/go-flags/go.sum new file mode 100644 index 000000000000..7503251e122b --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/jessevdk/go-flags/group.go b/vendor/github.com/jessevdk/go-flags/group.go index 9e057abd9f2a..181caabb2df8 100644 --- a/vendor/github.com/jessevdk/go-flags/group.go +++ b/vendor/github.com/jessevdk/go-flags/group.go @@ -34,6 +34,9 @@ type Group struct { // The namespace of the group Namespace string + // The environment namespace of the group + EnvNamespace string + // If true, the group is not displayed in the help or man page Hidden bool @@ -70,6 +73,13 @@ func (g *Group) AddGroup(shortDescription string, longDescription string, data i return group, nil } +// AddOption adds a new option to this group. +func (g *Group) AddOption(option *Option, data interface{}) { + option.value = reflect.ValueOf(data) + option.group = g + g.options = append(g.options, option) +} + // Groups returns the list of groups embedded in this group. func (g *Group) Groups() []*Group { return g.groups @@ -165,6 +175,18 @@ func (g *Group) optionByName(name string, namematch func(*Option, string) bool) return retopt } +func (g *Group) showInHelp() bool { + if g.Hidden { + return false + } + for _, opt := range g.options { + if opt.showInHelp() { + return true + } + } + return false +} + func (g *Group) eachGroup(f func(*Group)) { f(g) @@ -358,6 +380,7 @@ func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.Struc } group.Namespace = mtag.Get("namespace") + group.EnvNamespace = mtag.Get("env-namespace") group.Hidden = mtag.Get("hidden") != "" return true, nil diff --git a/vendor/github.com/jessevdk/go-flags/help.go b/vendor/github.com/jessevdk/go-flags/help.go index d38030500e8d..068fce15255e 100644 --- a/vendor/github.com/jessevdk/go-flags/help.go +++ b/vendor/github.com/jessevdk/go-flags/help.go @@ -72,6 +72,9 @@ func (p *Parser) getAlignmentInfo() alignmentInfo { var prevcmd *Command p.eachActiveGroup(func(c *Command, grp *Group) { + if !grp.showInHelp() { + return + } if c != prevcmd { for _, arg := range c.args { ret.updateLen(arg.Name, c != p.Command) @@ -79,7 +82,7 @@ func (p *Parser) getAlignmentInfo() alignmentInfo { } for _, info := range grp.options { - if !info.canCli() { + if !info.showInHelp() { continue } @@ -225,12 +228,12 @@ func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alig } var envDef string - if option.EnvDefaultKey != "" { + if option.EnvKeyWithNamespace() != "" { var envPrintable string if runtime.GOOS == "windows" { - envPrintable = "%" + option.EnvDefaultKey + "%" + envPrintable = "%" + option.EnvKeyWithNamespace() + "%" } else { - envPrintable = "$" + option.EnvDefaultKey + envPrintable = "$" + option.EnvKeyWithNamespace() } envDef = fmt.Sprintf(" [%s]", envPrintable) } @@ -305,7 +308,7 @@ func (p *Parser) WriteHelp(writer io.Writer) { } } else if us, ok := allcmd.data.(Usage); ok { usage = us.Usage() - } else if allcmd.hasCliOptions() { + } else if allcmd.hasHelpOptions() { usage = fmt.Sprintf("[%s-OPTIONS]", allcmd.Name) } @@ -393,7 +396,7 @@ func (p *Parser) WriteHelp(writer io.Writer) { } for _, info := range grp.options { - if !info.canCli() || info.Hidden { + if !info.showInHelp() { continue } @@ -489,3 +492,23 @@ func (p *Parser) WriteHelp(writer io.Writer) { wr.Flush() } + +// WroteHelp is a helper to test the error from ParseArgs() to +// determine if the help message was written. It is safe to +// call without first checking that error is nil. +func WroteHelp(err error) bool { + if err == nil { // No error + return false + } + + flagError, ok := err.(*Error) + if !ok { // Not a go-flag error + return false + } + + if flagError.Type != ErrHelp { // Did not print the help message + return false + } + + return true +} diff --git a/vendor/github.com/jessevdk/go-flags/ini.go b/vendor/github.com/jessevdk/go-flags/ini.go index e714d3d38d1c..60b36c79c44d 100644 --- a/vendor/github.com/jessevdk/go-flags/ini.go +++ b/vendor/github.com/jessevdk/go-flags/ini.go @@ -325,19 +325,19 @@ func writeCommandIni(command *Command, namespace string, writer io.Writer, optio }) for _, c := range command.commands { - var nns string + var fqn string if c.Hidden { continue } if len(namespace) != 0 { - nns = c.Name + "." + nns + fqn = namespace + "." + c.Name } else { - nns = c.Name + fqn = c.Name } - writeCommandIni(c, nns, writer, options) + writeCommandIni(c, fqn, writer, options) } } @@ -499,13 +499,21 @@ func (i *IniParser) matchingGroups(name string) []*Group { func (i *IniParser) parse(ini *ini) error { p := i.parser + p.eachOption(func(cmd *Command, group *Group, option *Option) { + option.clearReferenceBeforeSet = true + }) + var quotesLookup = make(map[*Option]bool) for name, section := range ini.Sections { groups := i.matchingGroups(name) if len(groups) == 0 { - return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name) + if (p.Options & IgnoreUnknown) == None { + return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name) + } + + continue } for _, inival := range section { @@ -537,9 +545,8 @@ func (i *IniParser) parse(ini *ini) error { continue } - // ini value is ignored if override is set and - // value was previously set from non default - if i.ParseAsDefaults && !opt.isSetDefault { + // ini value is ignored if parsed as default but defaults are prevented + if i.ParseAsDefaults && opt.preventDefault { continue } @@ -572,7 +579,15 @@ func (i *IniParser) parse(ini *ini) error { } } - if err := opt.set(pval); err != nil { + var err error + + if i.ParseAsDefaults { + err = opt.setDefault(pval) + } else { + err = opt.set(pval) + } + + if err != nil { return &IniError{ Message: err.Error(), File: ini.File, @@ -580,6 +595,9 @@ func (i *IniParser) parse(ini *ini) error { } } + // Defaults from ini files take precendence over defaults from parser + opt.preventDefault = true + // either all INI values are quoted or only values who need quoting if _, ok := quotesLookup[opt]; !inival.Quoted || !ok { quotesLookup[opt] = inival.Quoted diff --git a/vendor/github.com/jessevdk/go-flags/man.go b/vendor/github.com/jessevdk/go-flags/man.go index 0cb114e7482f..82572f9a7c17 100644 --- a/vendor/github.com/jessevdk/go-flags/man.go +++ b/vendor/github.com/jessevdk/go-flags/man.go @@ -3,42 +3,55 @@ package flags import ( "fmt" "io" + "os" "runtime" + "strconv" "strings" "time" ) +func manQuoteLines(s string) string { + lines := strings.Split(s, "\n") + parts := []string{} + + for _, line := range lines { + parts = append(parts, manQuote(line)) + } + + return strings.Join(parts, "\n") +} + func manQuote(s string) string { return strings.Replace(s, "\\", "\\\\", -1) } -func formatForMan(wr io.Writer, s string) { +func formatForMan(wr io.Writer, s string, quoter func(s string) string) { for { idx := strings.IndexRune(s, '`') if idx < 0 { - fmt.Fprintf(wr, "%s", manQuote(s)) + fmt.Fprintf(wr, "%s", quoter(s)) break } - fmt.Fprintf(wr, "%s", manQuote(s[:idx])) + fmt.Fprintf(wr, "%s", quoter(s[:idx])) s = s[idx+1:] idx = strings.IndexRune(s, '\'') if idx < 0 { - fmt.Fprintf(wr, "%s", manQuote(s)) + fmt.Fprintf(wr, "%s", quoter(s)) break } - fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx])) + fmt.Fprintf(wr, "\\fB%s\\fP", quoter(s[:idx])) s = s[idx+1:] } } func writeManPageOptions(wr io.Writer, grp *Group) { grp.eachGroup(func(group *Group) { - if group.Hidden || len(group.options) == 0 { + if !group.showInHelp() { return } @@ -48,13 +61,13 @@ func writeManPageOptions(wr io.Writer, grp *Group) { fmt.Fprintf(wr, ".SS %s\n", group.ShortDescription) if group.LongDescription != "" { - formatForMan(wr, group.LongDescription) + formatForMan(wr, group.LongDescription, manQuoteLines) fmt.Fprintln(wr, "") } } for _, opt := range group.options { - if !opt.canCli() || opt.Hidden { + if !opt.showInHelp() { continue } @@ -83,11 +96,11 @@ func writeManPageOptions(wr io.Writer, grp *Group) { if len(opt.Default) != 0 { fmt.Fprintf(wr, " ", manQuote(strings.Join(quoteV(opt.Default), ", "))) - } else if len(opt.EnvDefaultKey) != 0 { + } else if len(opt.EnvKeyWithNamespace()) != 0 { if runtime.GOOS == "windows" { - fmt.Fprintf(wr, " ", manQuote(opt.EnvDefaultKey)) + fmt.Fprintf(wr, " ", manQuote(opt.EnvKeyWithNamespace())) } else { - fmt.Fprintf(wr, " ", manQuote(opt.EnvDefaultKey)) + fmt.Fprintf(wr, " ", manQuote(opt.EnvKeyWithNamespace())) } } @@ -98,14 +111,14 @@ func writeManPageOptions(wr io.Writer, grp *Group) { fmt.Fprintln(wr, "\\fP") if len(opt.Description) != 0 { - formatForMan(wr, opt.Description) + formatForMan(wr, opt.Description, manQuoteLines) fmt.Fprintln(wr, "") } } }) } -func writeManPageSubcommands(wr io.Writer, name string, root *Command) { +func writeManPageSubcommands(wr io.Writer, name string, usagePrefix string, root *Command) { commands := root.sortedVisibleCommands() for _, c := range commands { @@ -121,11 +134,11 @@ func writeManPageSubcommands(wr io.Writer, name string, root *Command) { nn = c.Name } - writeManPageCommand(wr, nn, root, c) + writeManPageCommand(wr, nn, usagePrefix, c) } } -func writeManPageCommand(wr io.Writer, name string, root *Command, command *Command) { +func writeManPageCommand(wr io.Writer, name string, usagePrefix string, command *Command) { fmt.Fprintf(wr, ".SS %s\n", name) fmt.Fprintln(wr, command.ShortDescription) @@ -137,30 +150,27 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm if strings.HasPrefix(command.LongDescription, cmdstart) { fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name)) - formatForMan(wr, command.LongDescription[len(cmdstart):]) + formatForMan(wr, command.LongDescription[len(cmdstart):], manQuoteLines) fmt.Fprintln(wr, "") } else { - formatForMan(wr, command.LongDescription) + formatForMan(wr, command.LongDescription, manQuoteLines) fmt.Fprintln(wr, "") } } + var pre = usagePrefix + " " + command.Name + var usage string if us, ok := command.data.(Usage); ok { usage = us.Usage() - } else if command.hasCliOptions() { + } else if command.hasHelpOptions() { usage = fmt.Sprintf("[%s-OPTIONS]", command.Name) } - var pre string - if root.hasCliOptions() { - pre = fmt.Sprintf("%s [OPTIONS] %s", root.Name, command.Name) - } else { - pre = fmt.Sprintf("%s %s", root.Name, command.Name) - } - + var nextPrefix = pre if len(usage) > 0 { fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage)) + nextPrefix = pre + " " + usage } if len(command.Aliases) > 0 { @@ -168,17 +178,25 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm } writeManPageOptions(wr, command.Group) - writeManPageSubcommands(wr, name, command) + writeManPageSubcommands(wr, name, nextPrefix, command) } // WriteManPage writes a basic man page in groff format to the specified // writer. func (p *Parser) WriteManPage(wr io.Writer) { t := time.Now() + source_date_epoch := os.Getenv("SOURCE_DATE_EPOCH") + if source_date_epoch != "" { + sde, err := strconv.ParseInt(source_date_epoch, 10, 64) + if err != nil { + panic(fmt.Sprintf("Invalid SOURCE_DATE_EPOCH: %s", err)) + } + t = time.Unix(sde, 0) + } fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006")) fmt.Fprintln(wr, ".SH NAME") - fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuote(p.ShortDescription)) + fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuoteLines(p.ShortDescription)) fmt.Fprintln(wr, ".SH SYNOPSIS") usage := p.Usage @@ -190,7 +208,7 @@ func (p *Parser) WriteManPage(wr io.Writer) { fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage)) fmt.Fprintln(wr, ".SH DESCRIPTION") - formatForMan(wr, p.LongDescription) + formatForMan(wr, p.LongDescription, manQuoteLines) fmt.Fprintln(wr, "") fmt.Fprintln(wr, ".SH OPTIONS") @@ -200,6 +218,6 @@ func (p *Parser) WriteManPage(wr io.Writer) { if len(p.visibleCommands()) > 0 { fmt.Fprintln(wr, ".SH COMMANDS") - writeManPageSubcommands(wr, "", p.Command) + writeManPageSubcommands(wr, "", p.Name+" "+usage, p.Command) } } diff --git a/vendor/github.com/jessevdk/go-flags/option.go b/vendor/github.com/jessevdk/go-flags/option.go index 5f8525019979..f6d6941813be 100644 --- a/vendor/github.com/jessevdk/go-flags/option.go +++ b/vendor/github.com/jessevdk/go-flags/option.go @@ -80,10 +80,11 @@ type Option struct { // Determines if the option will be always quoted in the INI output iniQuote bool - tag multiTag - isSet bool - isSetDefault bool - preventDefault bool + tag multiTag + isSet bool + isSetDefault bool + preventDefault bool + clearReferenceBeforeSet bool defaultLiteral string } @@ -139,6 +140,57 @@ func (option *Option) LongNameWithNamespace() string { return longName } +// EnvKeyWithNamespace returns the option's env key with the group namespaces +// prepended by walking up the option's group tree. Namespaces and the env key +// itself are separated by the parser's namespace delimiter. If the env key is +// empty an empty string is returned. +func (option *Option) EnvKeyWithNamespace() string { + if len(option.EnvDefaultKey) == 0 { + return "" + } + + // fetch the namespace delimiter from the parser which is always at the + // end of the group hierarchy + namespaceDelimiter := "" + g := option.group + + for { + if p, ok := g.parent.(*Parser); ok { + namespaceDelimiter = p.EnvNamespaceDelimiter + + break + } + + switch i := g.parent.(type) { + case *Command: + g = i.Group + case *Group: + g = i + } + } + + // concatenate long name with namespace + key := option.EnvDefaultKey + g = option.group + + for g != nil { + if g.EnvNamespace != "" { + key = g.EnvNamespace + namespaceDelimiter + key + } + + switch i := g.parent.(type) { + case *Command: + g = i.Group + case *Group: + g = i + case *Parser: + g = nil + } + } + + return key +} + // String converts an option to a human friendly readable string describing the // option. func (option *Option) String() string { @@ -190,12 +242,13 @@ func (option *Option) IsSetDefault() bool { func (option *Option) set(value *string) error { kind := option.value.Type().Kind() - if (kind == reflect.Map || kind == reflect.Slice) && !option.isSet { + if (kind == reflect.Map || kind == reflect.Slice) && option.clearReferenceBeforeSet { option.empty() } option.isSet = true option.preventDefault = true + option.clearReferenceBeforeSet = false if len(option.Choices) != 0 { found := false @@ -229,8 +282,23 @@ func (option *Option) set(value *string) error { return convert("", option.value, option.tag) } -func (option *Option) canCli() bool { - return option.ShortName != 0 || len(option.LongName) != 0 +func (option *Option) setDefault(value *string) error { + if option.preventDefault { + return nil + } + + if err := option.set(value); err != nil { + return err + } + + option.isSetDefault = true + option.preventDefault = false + + return nil +} + +func (option *Option) showInHelp() bool { + return !option.Hidden && (option.ShortName != 0 || len(option.LongName) != 0) } func (option *Option) canArgument() bool { @@ -257,14 +325,17 @@ func (option *Option) empty() { } } -func (option *Option) clearDefault() { +func (option *Option) clearDefault() error { + if option.preventDefault { + return nil + } + usedDefault := option.Default - if envKey := option.EnvDefaultKey; envKey != "" { + if envKey := option.EnvKeyWithNamespace(); envKey != "" { if value, ok := os.LookupEnv(envKey); ok { if option.EnvDefaultDelim != "" { - usedDefault = strings.Split(value, - option.EnvDefaultDelim) + usedDefault = strings.Split(value, option.EnvDefaultDelim) } else { usedDefault = []string{value} } @@ -277,8 +348,11 @@ func (option *Option) clearDefault() { option.empty() for _, d := range usedDefault { - option.set(&d) - option.isSetDefault = true + err := option.setDefault(&d) + + if err != nil { + return err + } } } else { tp := option.value.Type() @@ -294,6 +368,8 @@ func (option *Option) clearDefault() { } } } + + return nil } func (option *Option) valueIsDefault() bool { @@ -339,6 +415,30 @@ func (option *Option) isUnmarshaler() Unmarshaler { return nil } +func (option *Option) isValueValidator() ValueValidator { + v := option.value + + for { + if !v.CanInterface() { + break + } + + i := v.Interface() + + if u, ok := i.(ValueValidator); ok { + return u + } + + if !v.CanAddr() { + break + } + + v = v.Addr() + } + + return nil +} + func (option *Option) isBool() bool { tp := option.value.Type() @@ -457,3 +557,13 @@ func (option *Option) shortAndLongName() string { return ret.String() } + +func (option *Option) isValidValue(arg string) error { + if validator := option.isValueValidator(); validator != nil { + return validator.IsValidValue(arg) + } + if argumentIsOption(arg) && !(option.isSignedNumber() && len(arg) > 1 && arg[0] == '-' && arg[1] >= '0' && arg[1] <= '9') { + return fmt.Errorf("expected argument for flag `%s', but got option `%s'", option, arg) + } + return nil +} diff --git a/vendor/github.com/jessevdk/go-flags/parser.go b/vendor/github.com/jessevdk/go-flags/parser.go index 0a7922a08a2e..3fc3f7ba1c2e 100644 --- a/vendor/github.com/jessevdk/go-flags/parser.go +++ b/vendor/github.com/jessevdk/go-flags/parser.go @@ -9,6 +9,7 @@ import ( "fmt" "os" "path" + "reflect" "sort" "strings" "unicode/utf8" @@ -29,6 +30,9 @@ type Parser struct { // NamespaceDelimiter separates group namespaces and option long names NamespaceDelimiter string + // EnvNamespaceDelimiter separates group env namespaces and env keys + EnvNamespaceDelimiter string + // UnknownOptionsHandler is a function which gets called when the parser // encounters an unknown option. The function receives the unknown option // name, a SplitArgument which specifies its value if set with an argument @@ -170,9 +174,10 @@ func NewParser(data interface{}, options Options) *Parser { // be added to this parser by using AddGroup and AddCommand. func NewNamedParser(appname string, options Options) *Parser { p := &Parser{ - Command: newCommand(appname, "", "", nil), - Options: options, - NamespaceDelimiter: ".", + Command: newCommand(appname, "", "", nil), + Options: options, + NamespaceDelimiter: ".", + EnvNamespaceDelimiter: "_", } p.Command.parent = p @@ -203,8 +208,7 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { } p.eachOption(func(c *Command, g *Group, option *Option) { - option.isSet = false - option.isSetDefault = false + option.clearReferenceBeforeSet = true option.updateDefaultLiteral() }) @@ -237,6 +241,7 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { p.fillParseState(s) for !s.eof() { + var err error arg := s.pop() // When PassDoubleDash is set and we encounter a --, then @@ -247,6 +252,20 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { } if !argumentIsOption(arg) { + if (p.Options&PassAfterNonOption) != None && s.lookup.commands[arg] == nil { + // If PassAfterNonOption is set then all remaining arguments + // are considered positional + if err = s.addArgs(s.arg); err != nil { + break + } + + if err = s.addArgs(s.args...); err != nil { + break + } + + break + } + // Note: this also sets s.err, so we can just check for // nil here and use s.err later if p.parseNonOption(s) != nil { @@ -256,8 +275,6 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { continue } - var err error - prefix, optname, islong := stripOptionPrefix(arg) optname, _, argument := splitOption(prefix, optname, islong) @@ -293,11 +310,13 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { if s.err == nil { p.eachOption(func(c *Command, g *Group, option *Option) { - if option.preventDefault { - return + err := option.clearDefault() + if err != nil { + if _, ok := err.(*Error); !ok { + err = p.marshalError(option, err) + } + s.err = err } - - option.clearDefault() }) s.checkRequired(p) @@ -515,8 +534,8 @@ func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg } else { arg = s.pop() - if argumentIsOption(arg) && !(option.isSignedNumber() && len(arg) > 1 && arg[0] == '-' && arg[1] >= '0' && arg[1] <= '9') { - return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got option `%s'", option, arg) + if validationErr := option.isValidValue(arg); validationErr != nil { + return newErrorf(ErrExpectedArgument, validationErr.Error()) } else if p.Options&PassDoubleDash != 0 && arg == "--" { return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got double dash `--'", option) } @@ -545,16 +564,37 @@ func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg if err != nil { if _, ok := err.(*Error); !ok { - err = newErrorf(ErrMarshal, "invalid argument for flag `%s' (expected %s): %s", - option, - option.value.Type(), - err.Error()) + err = p.marshalError(option, err) } } return err } +func (p *Parser) marshalError(option *Option, err error) *Error { + s := "invalid argument for flag `%s'" + + expected := p.expectedType(option) + + if expected != "" { + s = s + " (expected " + expected + ")" + } + + return newErrorf(ErrMarshal, s+": %s", + option, + err.Error()) +} + +func (p *Parser) expectedType(option *Option) string { + valueType := option.value.Type() + + if valueType.Kind() == reflect.Func { + return "" + } + + return valueType.String() +} + func (p *Parser) parseLong(s *parseState, name string, argument *string) error { if option := s.lookup.longNames[name]; option != nil { // Only long options that are required can consume an argument @@ -649,23 +689,7 @@ func (p *Parser) parseNonOption(s *parseState) error { } } - if (p.Options & PassAfterNonOption) != None { - // If PassAfterNonOption is set then all remaining arguments - // are considered positional - if err := s.addArgs(s.arg); err != nil { - return err - } - - if err := s.addArgs(s.args...); err != nil { - return err - } - - s.args = []string{} - } else { - return s.addArgs(s.arg) - } - - return nil + return s.addArgs(s.arg) } func (p *Parser) showBuiltinHelp() error { @@ -688,13 +712,3 @@ func (p *Parser) printError(err error) error { return err } - -func (p *Parser) clearIsSet() { - p.eachCommand(func(c *Command) { - c.eachGroup(func(g *Group) { - for _, option := range g.options { - option.isSet = false - } - }) - }, true) -} diff --git a/vendor/github.com/jessevdk/go-flags/termsize.go b/vendor/github.com/jessevdk/go-flags/termsize.go index 1ca6a8503c7e..829e477addfb 100644 --- a/vendor/github.com/jessevdk/go-flags/termsize.go +++ b/vendor/github.com/jessevdk/go-flags/termsize.go @@ -1,28 +1,15 @@ -// +build !windows,!plan9,!solaris,!appengine +// +build !windows,!plan9,!appengine,!wasm package flags import ( - "syscall" - "unsafe" + "golang.org/x/sys/unix" ) -type winsize struct { - row, col uint16 - xpixel, ypixel uint16 -} - func getTerminalColumns() int { - ws := winsize{} - - if tIOCGWINSZ != 0 { - syscall.Syscall(syscall.SYS_IOCTL, - uintptr(0), - uintptr(tIOCGWINSZ), - uintptr(unsafe.Pointer(&ws))) - - return int(ws.col) + ws, err := unix.IoctlGetWinsize(0, unix.TIOCGWINSZ) + if err != nil { + return 80 } - - return 80 + return int(ws.Col) } diff --git a/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go index 3d5385b0bca8..c1ff18673b1e 100644 --- a/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go +++ b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go @@ -1,4 +1,4 @@ -// +build windows plan9 solaris appengine +// +build plan9 appengine wasm package flags diff --git a/vendor/github.com/jessevdk/go-flags/termsize_windows.go b/vendor/github.com/jessevdk/go-flags/termsize_windows.go new file mode 100644 index 000000000000..5c0fa6ba2720 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_windows.go @@ -0,0 +1,85 @@ +// +build windows + +package flags + +import ( + "syscall" + "unsafe" +) + +type ( + SHORT int16 + WORD uint16 + + SMALL_RECT struct { + Left SHORT + Top SHORT + Right SHORT + Bottom SHORT + } + + COORD struct { + X SHORT + Y SHORT + } + + CONSOLE_SCREEN_BUFFER_INFO struct { + Size COORD + CursorPosition COORD + Attributes WORD + Window SMALL_RECT + MaximumWindowSize COORD + } +) + +var kernel32DLL = syscall.NewLazyDLL("kernel32.dll") +var getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo") + +func getError(r1, r2 uintptr, lastErr error) error { + // If the function fails, the return value is zero. + if r1 == 0 { + if lastErr != nil { + return lastErr + } + return syscall.EINVAL + } + return nil +} + +func getStdHandle(stdhandle int) (uintptr, error) { + handle, err := syscall.GetStdHandle(stdhandle) + if err != nil { + return 0, err + } + return uintptr(handle), nil +} + +// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer. +// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx +func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) { + var info CONSOLE_SCREEN_BUFFER_INFO + if err := getError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)); err != nil { + return nil, err + } + return &info, nil +} + +func getTerminalColumns() int { + defaultWidth := 80 + + stdoutHandle, err := getStdHandle(syscall.STD_OUTPUT_HANDLE) + if err != nil { + return defaultWidth + } + + info, err := GetConsoleScreenBufferInfo(stdoutHandle) + if err != nil { + return defaultWidth + } + + if info.MaximumWindowSize.X > 0 { + return int(info.MaximumWindowSize.X) + } + + return defaultWidth +} diff --git a/vendor/github.com/jessevdk/go-flags/tiocgwinsz_bsdish.go b/vendor/github.com/jessevdk/go-flags/tiocgwinsz_bsdish.go deleted file mode 100644 index fcc118601016..000000000000 --- a/vendor/github.com/jessevdk/go-flags/tiocgwinsz_bsdish.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build darwin freebsd netbsd openbsd - -package flags - -const ( - tIOCGWINSZ = 0x40087468 -) diff --git a/vendor/github.com/jessevdk/go-flags/tiocgwinsz_linux.go b/vendor/github.com/jessevdk/go-flags/tiocgwinsz_linux.go deleted file mode 100644 index e3975e2835f0..000000000000 --- a/vendor/github.com/jessevdk/go-flags/tiocgwinsz_linux.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build linux - -package flags - -const ( - tIOCGWINSZ = 0x5413 -) diff --git a/vendor/github.com/jessevdk/go-flags/tiocgwinsz_other.go b/vendor/github.com/jessevdk/go-flags/tiocgwinsz_other.go deleted file mode 100644 index 308215155eaf..000000000000 --- a/vendor/github.com/jessevdk/go-flags/tiocgwinsz_other.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !darwin,!freebsd,!netbsd,!openbsd,!linux - -package flags - -const ( - tIOCGWINSZ = 0 -) diff --git a/vendor/github.com/prometheus/alertmanager/asset/assets_vfsdata.go b/vendor/github.com/prometheus/alertmanager/asset/assets_vfsdata.go index 8f3cca6aa18b..26011bc2e726 100644 --- a/vendor/github.com/prometheus/alertmanager/asset/assets_vfsdata.go +++ b/vendor/github.com/prometheus/alertmanager/asset/assets_vfsdata.go @@ -151,9 +151,9 @@ var Assets = func() http.FileSystem { "/static/script.js": &vfsgen۰CompressedFileInfo{ name: "script.js", modTime: time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC), - uncompressedSize: 109876, + uncompressedSize: 108434, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xcc\xfd\x09\x5f\x1b\xbb\xf2\x20\x80\x7e\x15\xe8\xe1\xef\x2b\x1d\x17\x1d\x1b\x02\x49\xda\xe8\xfa\x11\x42\x12\x12\x12\x4e\x02\x59\x39\x4c\x46\x2d\xcb\xa6\x8d\x51\x3b\xb2\x1a\x42\xb0\xe7\xb3\xbf\x9f\x4a\xbd\xd9\xee\x36\xb9\xb3\xbd\x77\x4e\x7e\xc6\xd6\x52\x2a\x6d\xa5\xda\x54\x5a\xef\x27\x4a\x98\x28\x56\x44\xd1\x7b\x2f\x99\xc8\xb5\x89\xd1\x91\x30\x5e\x27\xcb\x58\xd3\x44\x81\x06\x43\xef\xb5\x34\x89\x56\x6b\xc6\xe7\x4c\x81\xf1\xfb\x4c\x83\x99\xe5\xc5\xae\x49\x51\x44\x93\x2d\x30\x90\x83\xd6\x79\x46\xb9\xb5\x0c\x1c\xd1\xa0\xe8\x6c\x46\x0b\x50\x97\x44\x96\x40\x6d\x83\x2c\x40\x99\x65\x50\x2b\xa1\x4b\x62\xc0\xc1\x2f\x37\x60\x48\x52\x6a\xe0\x31\x24\x45\x03\x72\x19\xda\x7f\xda\x66\x42\x24\xe4\xad\x96\x9b\x8d\x08\x2f\x35\xbb\x03\xbc\x68\x36\x59\x06\xf8\x7f\x00\x13\x4e\x12\x28\xe3\x52\x46\x46\x12\x51\x42\x66\x17\x44\x81\x0c\x5f\x86\xf9\x7f\x07\x3f\x41\x38\x2c\x60\x58\x46\x31\x21\x51\x09\xc5\x27\x10\x15\x28\x8a\x65\xb0\xff\xcf\xb0\x8e\x88\x80\x65\xbc\xcb\x88\x73\x12\x97\x10\x7f\x0a\x71\x81\x78\xb4\x0c\xf9\xff\x97\x7d\x89\x49\x04\x95\xbd\x29\x77\x47\x90\x7e\xa9\x3b\xcf\xa0\x5f\x74\x27\x5e\x06\xfe\xff\x67\x3d\xec\x93\x18\xea\xfa\x58\xee\xe4\x70\x81\xcc\x6d\x31\xc6\x94\xcf\xbb\xca\xef\x13\x9b\x1e\xd8\x76\x88\x29\xd5\x38\x70\x35\xa0\x40\x72\x7b\xbe\x0e\xc8\xbc\x16\x91\xa5\x8a\x47\x59\x45\x28\xba\xfc\x78\xb1\x2a\x24\xe5\xca\x24\x29\xd5\x1f\x14\xf5\xa1\x18\xc7\x9d\x65\x08\xc0\x17\x60\x10\x5e\x02\x33\x2a\x83\x81\x62\x8e\x76\xab\x00\x81\x58\x06\x45\x44\x09\x5a\x38\x0f\x0d\x8a\x65\xf0\xa4\x1a\x1e\x44\x95\x10\x49\x44\x67\x37\x5c\xaf\xc5\xec\x92\x14\xd3\xe9\xa6\xa6\x1f\x6b\x62\xf3\x24\xdb\xd7\x9a\xdf\x11\x45\x21\x61\xad\x4e\xb2\xa7\x3a\x49\xb3\x49\xe5\x79\x72\xc1\x0c\xd1\xcd\x84\x76\x32\xfa\x3f\xa3\xd0\x67\xd7\x73\x90\x0a\x38\xa6\x80\x23\x59\xab\x23\xf7\x54\xa3\xa1\xfd\xb0\x23\x9b\x4d\x6a\xce\xe5\x05\xd3\x3e\x07\xcd\x6c\x52\x7e\xf8\x8d\xa4\x1a\x98\x4b\x26\xe1\xc4\x1e\x2d\x74\x46\x61\xc2\xc8\x62\x03\xd9\x66\x39\x57\x17\x33\x0a\xab\x3a\x92\x01\x84\x24\xc5\x45\x52\xe0\xac\xd5\xe1\x7b\xb2\xc3\x9b\x4d\x9a\x9c\xf3\x0b\x66\xce\xf9\x45\x86\x41\x72\xae\x2e\x98\x86\x64\x46\xa1\xbe\x5b\x3a\x83\x9a\x8d\x94\x69\xb6\xb3\xb1\x32\xc5\x58\xe9\xf3\x24\x87\x2b\xcf\xcd\x05\x53\x20\xff\x1c\x5f\x0b\x4c\x22\x30\xcd\xec\xee\x31\xe7\xc9\x05\xe8\x7c\xe8\xf5\x1f\x42\xda\x6c\x77\x5a\x7b\x4c\x76\xe4\xe6\x66\x0e\x48\x2e\x00\xa2\x9d\xff\xa4\xaf\x15\x3d\x55\xc4\xf6\x75\x6e\x59\xfc\x6f\xcf\x0a\x52\x8c\x26\x07\x3b\x3b\x39\xe4\xa4\x12\x72\xbe\x7a\x26\xa3\x48\x48\xec\x41\x65\x39\xd7\xba\x2e\x5a\x57\x9b\xb2\x93\x21\xb3\x97\x34\x1a\x24\xc9\x71\xa3\x9d\x0c\x5f\x9e\x21\xd9\x4c\x28\x08\xd6\xea\x88\x3d\xd9\x11\xcd\x26\xe5\xe7\xc2\x4e\xb2\xb8\xc0\xa2\x2e\x27\xc9\x72\x9a\xd2\x2e\x2c\x91\x2f\x00\x5e\xb1\xa2\x4a\x53\x59\x93\x25\x62\x35\x89\x47\xd2\x1f\xc5\x03\xa2\x9a\x5e\xb0\xb6\x17\x29\x23\xb5\xe2\xa3\xc9\xbf\x3d\x0a\x7a\x46\x0b\x4e\xf2\xc6\x92\x65\x73\xa9\xe3\xdb\xb5\x43\xad\x63\x4d\xbc\x4b\x63\xc6\x93\xe0\xd1\xa3\x41\x64\x2e\x93\xd0\x17\xf1\xf5\x23\x39\xba\x7e\x24\x62\x2d\x1f\x85\xa3\x38\x7c\xd4\xf6\x5b\x7e\xeb\xd1\x65\xa4\xcc\xe4\x91\xd7\x54\x4d\xcf\xbf\xee\x79\x25\xaa\x33\x5e\x58\x0d\x20\xd9\xf9\x05\x24\xac\x87\x23\xda\x02\x49\x3b\x76\xd4\x0c\x93\xfe\x38\x1e\x13\x4a\x3b\x36\xcf\xf8\x1c\x8c\x1f\x62\x7e\x69\xe6\x72\xa8\xbd\x82\xb2\x47\x7d\xd2\x6e\xb5\xf6\x0c\xcd\x56\x8e\x3f\x4e\x26\x97\xe4\x04\xdb\xa5\xb0\xde\xea\x44\x7d\xa2\x18\x63\x3a\x2d\xe1\x52\xbc\x38\x1c\x4a\x61\xbc\x75\x66\xee\xc6\x32\xee\xaf\xa9\xe9\x54\x25\xa3\x91\x25\x85\xf9\xb7\xac\x8a\x97\x35\xec\xb1\xbc\x78\xa3\x71\x43\x76\x28\xac\xb7\xf3\x59\x4e\xd6\x22\xb5\xa6\xfc\x8d\xbd\x56\xa3\x41\x14\x8b\x8c\x25\x5b\xda\xfe\xb5\x88\x28\x1a\xf5\xc9\x7a\x8f\x28\xdc\x84\xf6\xc3\x34\xdb\xb6\x7b\x29\x56\xed\x4e\x86\x1e\x52\xd7\x0d\x76\x4d\xc6\x14\x6e\x59\xf5\xb4\xae\x8f\xd3\x35\x5a\x4c\xde\x5d\xb6\x46\x2b\x7b\x97\x0d\x0f\x8e\x44\xb7\x15\xa8\x3d\xdd\xdd\x6c\x07\x6d\x3b\x16\xeb\xca\xdf\x48\xf3\x89\x61\x77\x44\x59\xa2\xea\x73\x4a\xbb\x26\x48\x13\x42\xd0\x7e\x88\x09\xf6\x97\x00\xed\x0b\xb7\xbc\x3b\xca\x0f\x91\x26\x37\x1a\xeb\xf3\x95\x3b\x8a\x61\x3d\x4b\x9d\xf3\x39\x34\xd3\xa9\x85\xd6\x6d\x07\xda\x0f\x2d\x02\x2d\x77\x98\xfc\xaa\xe9\xa7\xeb\x15\xdd\x6b\xcd\x28\x1c\xd6\x92\xf1\xb4\x50\xbb\x7e\x17\xb4\xf6\xee\xb2\x4d\x5d\x5b\x82\xd5\x16\x71\x74\xcc\x65\xe7\x3d\xd9\x6b\x75\x27\x26\x30\xdd\xd0\x04\x7d\x33\xa3\x14\xae\x58\xab\x98\x8d\x93\x32\xf0\x7b\x1e\x28\x08\x03\x3d\x2b\x56\xf0\xfe\x3c\xe5\xc9\x4a\x80\x08\x4c\xa9\xd4\x69\x89\x4f\x52\x45\xf2\x8f\x32\x5a\xf7\xb3\x7c\x05\x4a\x5c\x81\xee\x64\x54\xe7\xf2\x62\x3e\x43\xa7\x47\xa6\xcd\xc8\x3a\x81\x83\xff\x91\x5d\x93\xaf\xa5\x95\xf4\xd5\x81\xb7\xeb\xc8\x0a\x9b\x6a\x50\x5a\xf6\xf9\x3a\x6a\xea\x74\xe9\x84\x59\x92\xee\x38\x84\xde\xbb\x35\x90\x2e\x80\x4e\x89\x68\xdb\xc5\xe2\x52\xa9\x64\xd2\x0f\x8b\xa2\x73\xf8\x9c\xb1\xfb\x8d\xa0\x35\x2b\x10\x7a\x3f\x37\x98\x1b\x41\x1b\xf2\x01\xb5\xe5\x3f\xb1\x6b\xf2\xbe\x84\xff\xb1\x1d\xb5\xac\x59\xcd\xce\xc0\x30\x95\xd2\xe4\x8e\xd9\xdc\xec\x50\x6d\x1b\x3e\x37\xf3\x67\x58\x5e\xfd\xc5\x7c\xf5\xf3\x8b\x12\xda\xda\x51\x17\xe5\xf3\x52\x4d\x5b\xee\xcb\x4a\x6e\xe8\xfc\xa2\x83\x5b\xc4\x58\x46\xc5\x6e\x08\x30\xcc\xd8\x51\x70\xe0\xf0\xa0\x42\x92\xc7\x0b\x72\x77\x6c\x59\x52\x0a\xbf\x19\x31\x0b\x90\x2d\xd9\xcb\x89\x4e\x19\x76\xa3\x21\xe7\x1b\x00\x1c\x66\x9a\xb8\x66\x0e\x8a\x66\x40\xce\x37\x95\xd8\xa6\xa2\xa5\x76\x2c\xff\x5b\x1c\x62\x8b\x2d\x35\x1a\x49\x55\x73\x90\xb0\xc4\x0f\x29\x77\x8d\x1e\xcd\x37\x0a\xc9\x7c\xc3\xdc\x36\x2c\x2b\x1a\xb6\x8c\x73\xd6\xb4\xa8\x6e\xba\xd1\xe0\xf5\xed\x03\x67\xdc\x0f\xa9\x70\x58\x0c\x96\xb1\x00\x3e\x8f\x89\x58\xd8\xf9\x06\x8a\xbd\x77\x4c\xec\xa2\xf0\x27\xb1\x36\x75\x14\x08\xa9\x3d\x92\xfa\x19\xfe\x83\x37\x73\xe4\x4a\xfe\x11\x34\xb7\x81\x86\xb6\x74\x79\x57\x30\xc6\xfa\xa6\xdb\x0a\xec\x97\x89\x41\xba\x8d\x8d\xd4\xd1\x32\xd5\xb4\x2c\x19\x7c\xaf\x25\x98\x6a\x73\x05\xc7\xa0\xfe\xc2\xda\xaf\xeb\x6b\x3f\x5a\x55\xfb\x91\x9e\xb6\x30\xfb\x1d\x37\x97\xfe\x38\xbe\xad\xe7\x5a\xfe\x4b\xd5\x12\x5b\xfd\x5f\x2a\xeb\x7e\xcb\x9e\xc9\xdd\x1b\xd2\x6e\xd3\xa0\xb5\x67\x1a\x0d\xb5\xd7\x9a\x4e\x8d\x3d\x66\x5b\x7b\xaa\x6b\x9a\x2a\x30\x8e\x03\xc5\x16\xb9\xe1\x6a\x8b\x22\x2d\xfa\xc0\x30\x45\xc8\x68\x04\x3f\xdd\xf7\xfe\x28\x8e\x35\xbc\x73\x3f\x74\x9c\xa8\x1e\x3c\x77\x3f\x46\xf1\xa0\x53\xd7\xa7\x46\x63\x55\x8f\xa7\xd3\x55\xb9\xeb\x8c\x59\x26\xcb\xe2\xf3\x92\xad\x9a\xb0\xce\x7f\x94\xf9\x67\xfc\xb5\x1b\x4e\xce\xb4\x2f\x2e\xb9\x3e\x88\x7b\x72\xdf\x90\x84\x76\xf8\xde\xce\xce\xd6\xb3\xdd\xe9\x74\x67\x77\xbb\xfd\x6c\x8f\x77\x49\xca\x85\x9f\x3a\x3e\x9c\x82\xe5\xcc\x83\xf9\xd4\xa6\x3e\x4f\x9a\x6d\x97\xc9\xb6\xe8\x2c\xe7\xb8\x86\x71\xa4\x88\xe7\xd1\x95\x22\xcf\xf9\x05\xcc\x71\xce\x4e\x3a\xc9\x11\xb4\x1c\x91\x58\xc2\x33\x69\x36\x41\xcc\xe3\x2a\xa6\x53\xc2\x9b\xae\x82\x45\x12\x2c\x7a\x9c\x52\x4b\x1c\x70\xaf\xf3\x1c\x33\x53\xc2\xac\xf3\x1f\x09\x4d\x19\x5a\xc6\xa1\x65\xfe\x18\x2d\x93\xa3\xe5\x44\x25\x8b\x9a\x65\x2a\x0a\x46\x1d\x57\xc2\xdf\xec\x4f\xd0\xb1\x22\x57\x8a\x4a\xc2\x50\xe8\xe2\xf3\xa8\x48\x9c\xc9\xdd\xed\xad\xd6\x74\xba\xf3\x64\xfb\xf1\xf6\x1e\x9f\x4e\xad\x08\x72\xbe\xb9\x29\x2f\xac\xb4\x91\x61\x91\x2c\x60\x01\xaf\xea\xd6\xa2\xf6\x27\xe3\x11\x32\xaf\x33\x0a\x9f\xeb\x4b\xe1\xd0\x62\xa1\x6f\xec\x0f\x05\xaa\x3f\x58\xc4\xee\x80\xce\xe4\x2c\x7b\x46\x27\xf3\x8b\xc2\x50\xcb\x77\x24\xf3\xbd\x4e\xa6\x53\x62\x8b\x6f\x6e\x9a\x8b\xa6\x74\x4b\x42\xd2\x9c\xb7\x6e\xcd\x32\x26\x3b\x1d\xfe\xb7\xec\xff\x15\x26\xeb\x0b\xa8\xb4\x67\x39\x4e\x14\x94\xaa\x19\xde\xcd\xf6\x9e\xf6\x23\xd5\x93\xbf\x4e\xfa\x6e\x8c\x75\x5d\x51\x4b\x1e\x17\xca\x9a\xda\xb2\x19\x1b\xb4\x97\xf7\xd2\xf2\xee\x23\x3e\x31\x47\x39\x00\x96\xe7\x6d\x66\xc5\xed\x11\xbd\x0c\xd3\x0d\x57\xce\x59\x45\x7d\x62\xf6\xda\x19\x33\x78\x56\xe2\xfb\x5a\x80\x5c\xca\x66\x7b\xcf\x0e\x4d\x81\x2b\x0a\x77\x19\x73\x22\x29\xc8\x26\x33\xf3\x2c\x09\x4e\x56\x52\xd7\x1d\xcb\x09\xb6\xa0\x97\xb1\x82\x75\x04\xd4\x16\x6b\x83\x2c\x8a\x15\x6a\xe0\xa5\x72\xdb\xd0\x0f\x14\x0c\x32\xce\x52\xac\x6a\xfa\x31\x32\xec\x97\x81\x9a\xa5\x88\xc6\xb5\xe3\x8e\x0d\x9d\xeb\x0b\x3b\x3b\x7d\x55\xbf\x5d\xd2\x72\x60\xb0\x64\xa8\xaa\x79\xbf\xc5\xc2\x20\x2f\xea\xd9\xb7\xe5\xc2\x90\x5c\xac\x62\xba\xaa\x2a\x00\xc7\x2a\x49\x65\x95\x92\x66\x72\xa1\x12\x08\xac\xc6\x6b\xaa\x95\x54\x90\x4b\x15\x21\xc2\xaa\xa2\xb6\x2a\xc4\xab\x2a\x43\x7c\x51\x75\x1a\x19\x7d\x97\x55\x1a\xd9\xa4\x37\xa7\x27\xef\xfd\x31\xd7\x13\x89\x8c\x9b\xe0\x46\x5c\x96\x44\xae\x1b\x43\x86\xa4\x67\xc0\x3b\xbb\x8c\x26\x6b\xd1\x64\x4d\xc5\x66\xed\x86\x8f\xa2\xde\x9a\xad\xb9\xbe\xe6\x35\x95\x7f\x2d\x27\x13\x3e\x90\x30\x56\x16\x06\x9d\x59\xde\x69\x52\xbb\x12\xb0\xd9\x5b\xe5\xf8\xc4\x62\x25\x8e\xd2\x52\x93\xdb\x08\x51\xf0\x37\xe8\xbd\xe0\x13\xb9\xb6\x1d\xa4\x2a\x88\x30\x8e\x47\x92\x97\x34\x10\xba\x7b\x69\xd9\xcd\x60\x43\x11\x8f\xaf\x3d\x3f\x39\x39\xf6\x2c\xcf\x88\xb5\xb6\xb2\x5a\x2a\xb9\x0e\xa5\x2e\xf4\x00\xba\x8b\xc5\xd5\xda\xd1\xfb\x33\x5b\x3c\xd8\xdc\x6a\x3f\x7e\xf2\xf8\xe9\xf6\xee\xe3\x27\x7b\xba\xd1\xd0\x7b\xc5\xef\x46\x83\xb4\xa6\x9a\xa2\xc2\xc0\x35\xb5\x1e\x4d\x5e\x46\x2a\x32\x76\xb4\xa6\x53\xfd\x5f\xed\x45\x68\x58\xcc\xa1\xf0\x78\x01\x85\x1a\xbc\x5f\x1e\x9f\xec\x9f\x15\x88\xef\x66\xb5\x16\x05\xcf\xac\x96\x5e\x8b\xd4\xc4\x70\x25\x6c\xe2\x29\x16\xc2\x9c\xa6\xe7\x65\x20\x4f\xcf\x3e\x1e\xbd\x7f\x55\xc0\x7c\x16\x64\xd4\x2f\xd5\xea\xd8\x0a\xca\x17\xae\xbc\x4d\x2c\xca\xee\x64\x65\x2f\x0d\x71\x13\xea\xd2\x9f\x64\xe9\xc8\x61\xf9\xd1\xc4\x71\x5a\x9a\x76\x6f\x94\x53\x8f\xc0\x71\xd6\xfe\xf1\xd1\x69\xa9\x47\x4f\x1f\xae\xd9\x53\x69\x55\xb5\xb6\xff\xf1\xe3\xfe\xb7\xa2\x72\xbb\x15\x64\x54\xb6\x57\xa9\xb5\xd2\x85\xae\x6a\x3a\x5d\x27\xc6\xc9\xf9\x19\x11\x4e\x81\x9e\x3c\x7f\x73\x78\x70\xb6\x76\x1b\x99\xcb\x35\xbe\xd6\x8f\xe4\xa8\xb7\xa6\xf8\xb5\xec\xad\xfd\x0f\xaf\x69\x9a\xde\xff\xc0\x06\x1d\xad\x1e\xa5\x48\x9d\x9b\x42\x65\xda\x93\x44\xd2\xae\x0c\x70\x3b\x6c\x18\xbb\xcf\x50\x74\x72\x28\xb6\x03\xc7\x9f\x28\x5f\xa2\x46\x60\xb1\x9f\x0b\xc8\x14\x3d\x8c\xfa\x44\xe7\xe7\x51\x32\x57\x6c\xed\xf8\xe4\xfd\xab\xc3\x8f\x6b\x1c\x61\xad\xbd\x97\xb2\xb7\x86\xc7\xc6\x9a\xd7\x4c\x9a\xde\x5a\x98\x98\xb5\x58\x8d\xee\xd6\x26\x52\xae\x79\xcd\x0c\x4c\xd3\x5b\x93\xca\xe8\x48\x4e\xb0\x81\x52\x6f\x92\x9a\xde\x5c\x1b\x48\xe6\x7a\xb3\x15\x3c\x38\xcc\x0f\x74\xd0\x8d\x76\x3e\xa4\x9c\x15\x47\xa1\x70\xd3\x83\x1d\xbf\xe4\x93\x93\x5b\xf5\xb7\x8e\xc7\x52\x9b\x3b\x22\x28\xbd\x2f\xe1\x2b\x2e\x70\x7c\xd6\x11\x59\x5a\x26\x47\x1b\x06\x44\x8a\x31\x67\xef\xc9\x09\x71\xbf\xa0\xe0\x7a\x2f\x0d\xf9\x6d\x48\xd1\xa5\xed\x20\x6b\x3f\x62\xca\xef\x43\xcc\x94\x3f\x80\x3e\x6b\x75\xfa\x7b\x71\x76\x7a\xf7\x9b\xcd\x14\x81\xf8\xbc\x7f\x91\x4e\xcf\x7c\xf3\xb2\x13\xb1\x88\xd8\xc6\x4a\x2d\x45\x59\x2b\x8f\x83\x02\xfd\x85\xb1\xc6\xe4\x4b\xac\x69\x89\x84\x4c\x6b\xec\xe4\x78\x85\xec\x0c\x26\x16\xab\xce\xc4\x0f\x3b\x13\x36\xf1\xc3\x14\x99\x89\x53\x0f\x45\x7d\xb2\x80\x4a\xc8\xde\x5b\x80\x10\xe6\xc8\xdc\x18\x32\xc0\x9e\x87\x34\xef\x7a\xb0\x40\xc8\x95\xcf\x33\x3a\xed\x4a\xb4\x4a\xfb\x5d\xd9\x9e\x15\x6a\xa0\x9b\x0a\xc6\x5c\x3f\x60\x76\xb8\x77\xda\x0a\x47\xcd\xd1\xea\x90\x8e\xa2\x98\x9f\xc4\x6b\x63\x8f\x29\x9c\x44\xb4\x54\x08\x9f\x97\xc6\xd4\x8a\x18\x25\x15\x7a\xaf\x6c\x40\x1d\x92\x1b\x09\x39\x1a\x15\xe6\x54\x67\xd2\x2a\x6a\x6f\xcc\x9f\x3f\xf9\x91\x76\xf8\x6b\x2c\x85\x89\xd4\xc0\x1e\x62\xf9\xe1\x55\x78\x8b\xa8\x5c\x09\xb8\xac\x3c\x57\xfe\x86\x95\x6a\x73\xad\xf1\x7a\xbb\xb3\x74\x70\xb5\x82\xf9\x29\x50\x3e\xb7\x70\x7c\xde\x49\xcf\xb5\xf4\xa0\x4a\x0f\x8b\x94\xfa\xcf\x11\xe1\xf5\xd6\x22\x01\xf7\x05\xc2\x10\x19\x51\x4e\x29\x6c\xb6\x75\xd3\x62\xd7\x2a\xd7\x58\xe7\x64\x34\x87\xd0\x43\x08\xbd\x46\x63\xb9\x54\x09\x57\x89\xa5\x64\x55\xa9\xed\xa2\x54\x1f\x4b\xf5\x1b\x8d\x4b\x5b\x6a\x00\xda\x1f\x14\xdb\x21\x2f\x75\x89\xa5\x2e\xab\x60\x15\xc7\x4d\x01\xa0\xb4\x04\x2f\xeb\x39\xed\xf5\x82\x4d\x2f\x26\xa1\xc4\x72\x77\xe4\x9e\x41\x33\xa9\x5d\x80\xb6\x61\x34\xd9\x9d\xcb\x8b\x3a\x83\xc3\xa0\x96\x65\x41\x26\xc9\x9d\xc7\x51\xff\x8e\x20\xf3\x02\x96\x1c\x82\xa2\x4d\xcf\x2b\xb3\x31\x63\x55\xad\xb0\xbe\x9d\x4f\xb7\xed\xdd\xad\x60\x83\xcd\xb9\xba\x60\xae\x1d\x93\xf2\xd6\xbf\x14\xb3\xc0\x93\xd1\xa8\xd4\xdc\x61\x09\xec\xfd\x46\xd0\x02\x6e\x99\xf1\x3c\xfb\x6a\x3e\xbb\xbd\x90\xbd\x3f\x9f\xbd\x05\x61\xa0\x40\x04\xb6\x0d\xc7\xfd\x9f\xae\xe0\xfe\xb7\xb1\x74\x0f\x05\x0a\x18\xae\x28\xf8\xb8\x54\x10\x7b\x72\xa0\xca\x76\x82\x23\x44\xc2\x69\x9a\xb1\x0b\x32\x38\x50\xcd\x66\x2a\x86\xe0\x28\x5f\x06\xe7\x17\xb3\x8c\xa2\xbe\xc7\x51\x29\x69\xab\x4f\xca\xd4\x61\x5f\x91\x32\x49\x50\xe4\x50\x91\xa3\x74\x6b\x97\x36\xf7\x8f\x14\x49\xe5\x5f\x3a\xe1\x4b\x53\x78\x8f\xc2\x3c\x9a\x03\xe6\x7a\x53\x9e\x97\x05\xf0\x3f\x5c\x2e\x60\x33\x57\xd8\x84\xeb\xe2\x57\xc5\xd6\xdb\x70\xa6\xac\xd4\x57\x28\xf1\xb1\x4e\xd4\x27\x67\x2a\x55\xa2\x53\x58\xff\x9a\xaa\xda\x6d\x8d\x56\x47\xb1\x33\xe5\x4f\x2e\xa3\xbe\x21\xb4\x43\x3f\xd9\x0a\x1d\x84\x55\x9a\xb5\x4f\xd8\x5f\x34\x3d\x69\xbf\x9f\x0a\xe8\xca\x6e\x43\x7f\xc3\xee\x8c\x96\xb3\xe0\xb5\xed\x9f\xbc\xdc\xc0\x8a\xb9\x03\xa4\x5a\xaa\x43\xb5\x3f\x60\xf6\x67\x84\xd4\xd9\xee\x39\xd7\x3f\x0b\x10\x33\x42\x62\xc1\xd9\xd3\x2a\x2b\x39\x93\xa3\x89\xb4\xc8\xa3\xd7\x49\x4e\xcb\xe3\xa8\x87\x45\x05\xb6\x1f\xce\x8d\x8e\x05\xa6\x00\xe7\x6b\x46\xf1\x20\xd8\x71\x38\xa5\x48\x6a\xff\x72\x7e\x03\xa7\xcd\xf7\xb1\xf9\xcb\x6c\x1c\x28\x36\xbd\x66\x31\xb1\xcb\x0e\x75\xa1\xad\xa0\x6d\x65\x4f\x5b\x14\xa2\x40\xfb\x83\x19\x64\x75\x7b\xb3\xd9\x6c\x85\xcc\x78\x6c\xa7\x4c\x82\xf2\xc5\xbe\xfd\xd8\xb1\x1f\xad\xe2\x18\x59\xf6\xd3\xa1\xf7\xb3\xd9\x9c\xa4\x72\xbc\x20\x2e\xba\x13\x6f\x48\x26\x0a\xdc\x31\xd2\xd5\x7e\x7f\xc4\x07\x93\xc0\x8e\xce\x5a\x8b\xd2\x0e\x9e\x7f\xd3\xe9\x0d\x49\xd5\xb2\x11\xbb\x9f\x41\xcc\x88\x60\x86\xe0\x21\xe8\x73\xe8\x33\x4e\x26\x10\x53\x08\x59\x85\x96\x61\xde\x90\xf5\x42\x65\x3a\xb1\x17\x68\xe5\x4a\x7c\xde\x68\x10\x62\x98\x99\x4e\xef\x67\xf4\x5c\x5e\xb0\xc4\xe7\x44\xa2\x01\xd8\x96\x60\x5f\x14\x49\x4a\xfa\x2f\x33\x23\x11\x4c\x4a\x9d\x9a\xb8\xb6\x44\xaa\x7a\x8f\x29\xf4\x49\x6c\x4f\x65\xd0\x14\x3e\x28\x12\x81\xf0\x43\x48\x48\x4c\x73\x18\xf3\xa9\x10\x76\xef\xc7\xb1\x36\x93\x20\x9c\x05\xf7\x8e\x7c\xbc\x50\x68\x9b\xcb\xda\xf8\x52\xea\x90\x64\xf7\x03\xd4\x1d\xb8\x31\x9a\x81\x65\x9f\x05\x70\xcb\xe7\x83\xb0\xac\x34\x20\xaf\x96\xbb\x43\xf8\x97\xec\x48\x91\x21\x39\x55\xf9\x64\xad\x95\x5d\xad\x30\x47\xc1\xfd\x46\xb0\x03\x61\x50\x5e\x86\x8e\xb4\x28\x9f\xcf\xa9\xd3\xfd\x8d\xee\x01\xe1\x20\x91\xec\x06\xa2\xd1\x88\xba\x47\xe8\x8b\xa8\xfd\x08\xb4\x3f\xb4\xa9\x07\x98\x20\xba\xda\xb7\x6b\xcc\x26\xd9\xa5\x00\xca\x0f\xa9\x23\x14\xbf\xff\x94\x50\x68\x7f\x40\x16\xe9\x44\xcd\x61\x33\x24\x1f\x15\x28\xff\x12\x52\x7a\xae\xe7\x57\xdf\x9b\xd5\xce\x64\x48\xe5\xaf\x02\x0d\x23\x4b\xe9\x0b\xa2\xf1\x7d\x91\xd4\x5f\xdb\x7c\xdb\x87\xd7\x2b\x69\xbc\x0a\x14\xc4\x0b\x4a\xa3\x0f\x0b\xce\x20\x25\xfb\x2b\x7a\x00\xfc\x54\x64\xbd\x05\xb8\xcb\xec\x69\x05\xf6\x77\x1b\xf7\x8b\xfb\xad\xa8\x25\xbf\xe7\xc9\x85\xed\xa2\xd7\xff\xe5\x01\x0f\xe4\x79\x72\x31\x9d\xde\x47\xc1\x19\x0c\x83\xb3\x39\xb7\xb7\x9f\xa5\x4d\x9c\x32\x59\x3a\x67\xb2\x32\xd9\x4b\xfb\x57\xc0\x19\xe9\xb3\x04\x42\x26\x61\x48\x54\xf7\x85\x3a\xef\x5f\xf8\x32\x70\x7f\xfb\x73\xac\x62\x61\xdc\x0c\x3b\x1a\x0d\x68\x3f\xa9\x25\xa1\x63\x4b\x70\xf3\x53\xda\xb2\x99\x85\x81\x0c\x69\x9d\x39\x4f\x2e\x18\x89\x18\xb7\xdb\x37\x46\x65\x37\x2d\xe1\x0d\xaa\x1b\xfb\x11\x7b\x4f\x22\x88\xfd\x88\x06\xb1\x3f\x4c\x7f\x0c\x29\xc4\x34\x57\x4e\x14\x76\x3d\xed\x5f\x77\x84\x1f\x76\x04\x13\x7e\x48\xb1\xaf\x76\xd7\xd9\xde\xa6\x0d\x77\xe6\xd4\x20\x88\x46\x3a\x26\x7e\x0c\x06\xee\xc7\x81\xf6\x15\xfc\x0c\xe4\xcc\x2d\xca\x08\x62\xe8\x43\x58\x0c\xe0\x3b\xec\xf2\x0b\x75\xae\x2e\x1a\x8d\x1b\xb2\x5d\x1a\xdb\xe7\xf3\x6b\x0f\x4b\x02\x96\x64\xf7\x32\x78\xa9\x40\x07\x1a\x78\xf0\xb7\x9a\xc1\x9b\xfc\x78\x7c\x59\xcb\x28\xcd\xf9\xd2\xfc\x9d\xef\x3e\x03\x9c\x9d\x5f\x80\x60\x08\xd9\xd7\x10\x31\x62\x58\x0b\x16\x36\x89\x9b\x90\x89\x34\x67\xd1\xb5\x8c\x93\x12\x11\x4f\x0f\x72\xbb\x73\xc0\xe4\x13\x52\xca\x16\x23\xc9\x75\x56\x4d\xa3\x0a\x2a\x2b\xe5\xda\x0c\x59\xe4\xfa\xe5\x8b\x05\xae\x2b\x3f\x22\x53\x43\x2a\x2d\x14\xe1\x1c\xa4\x65\xc2\x04\x41\x77\x8e\xcc\xa4\x94\x31\xa1\x09\xba\xe0\x25\x17\x24\x9f\xa9\xb5\x68\x46\xe1\x7e\x92\x84\x13\xa1\xa3\x50\xce\x51\x21\x9e\x1d\xf9\x33\x48\x54\x75\x11\xd7\x7f\xc2\x19\x4f\x6d\x06\x94\x96\xd4\xda\x1d\xbd\xd7\x9a\x4e\x39\xda\x26\x84\x24\x1a\xda\x74\xe6\x76\xf0\x2b\xd5\xa9\xa1\x42\x55\xd2\x11\xda\x69\x69\xc6\x8b\x7d\x56\xcc\x4b\x54\x4f\xf6\x23\x25\x7b\x85\xb8\xdf\x8b\x45\x72\x2d\x95\xe9\x66\x5f\x82\x32\x21\xff\x96\x73\x4f\x7c\x3c\x96\xaa\x77\x70\x19\x8d\x7a\x76\xd8\xab\xce\x5d\xb7\x3f\xa5\xaf\xe2\x9e\xcc\x1d\x99\xfc\x31\xd7\x52\x99\xf7\x71\x4f\xfa\x5a\x8e\x47\x5c\x48\x07\xe4\x5a\x13\x55\x3e\x8d\x67\x14\x12\x0a\xf7\x73\xf4\xe7\x6d\x25\xd3\x8b\x5c\x90\x2e\xaf\xcc\xb2\x5e\xf6\x01\xab\x5c\xab\x34\xff\xf7\x19\x45\xe1\x1d\xd9\x64\x89\x1f\x4e\xa7\x2d\x48\x2d\x6b\x49\x61\xf3\x6b\x16\x36\x33\x24\xba\x22\x10\xd0\x0b\x7a\x1a\x5d\x35\x03\x03\xfd\x80\x43\x18\x48\x64\x1e\x48\xca\x09\x80\xfe\xbf\x82\xe0\x9f\xa1\xb8\xf5\x47\x28\x3a\x17\x16\xbd\x8a\x9d\x1f\x06\x0a\x8f\x98\x30\x68\x37\x89\xc6\xc6\xe9\xdc\x04\x49\xbd\x50\x67\xc7\x1e\x47\x70\x1d\x68\xb8\xca\x0e\xfc\x59\x0d\x09\x91\x9a\x9c\x2b\xd0\x17\x15\x2c\x99\x63\x24\x33\x9b\x88\xae\x97\x9e\x52\x18\x60\xaa\xa0\x64\x5e\xd4\x33\x54\xcc\x6b\xb6\x82\x57\xcc\xe1\x80\xac\x82\x54\x78\x57\x23\x2c\xa1\x19\x59\x69\x81\x28\x81\x83\xa4\x0a\x60\xd9\xeb\x7a\xf6\x07\x16\x8a\x39\x80\xc0\xab\x40\xce\x3b\x62\xcf\xfe\xc8\x86\xb1\x00\x16\x44\x15\xe0\x45\xd7\xec\xd9\x1f\xda\x39\x96\x80\x43\x54\x05\x7e\xd9\x57\x7b\xb6\x60\x0d\xe9\x43\x08\x13\x18\xc1\x0d\xf4\x60\x03\xae\xe1\x72\xae\x89\xa5\xdc\xaa\x46\x34\x0b\xc1\xb0\x09\x48\x36\x82\x84\xdd\x00\x67\x96\xf7\xdc\x80\x88\x5d\x43\xcc\x2e\xe1\x29\x63\x8c\x28\xd6\xa7\x55\xae\xe1\x10\xd7\x39\x87\x93\xd8\x2d\xd1\x25\x7b\xcd\xac\xde\x63\xc5\x72\x42\xbc\xe5\x95\xf8\x2d\x0a\xd1\x8a\x5d\xe8\xf1\x76\xb9\x30\xc4\x2b\xcb\x6e\xcd\x95\xed\xaf\x2c\xbb\x5d\x2e\xdb\xa9\xdb\x63\x58\xf4\xb1\x2d\xaa\x21\x0e\xee\xfb\x58\xc3\xcc\xe6\xc8\x40\xa8\x0b\x3a\xed\xd9\xf3\x6e\x6c\x3c\x2b\xbc\x79\x63\x2f\x50\x35\xfb\xdf\x0e\x02\x8a\x86\x1b\xdd\x21\x11\x1a\x2c\x6b\x43\x0c\x53\x90\xb0\x81\x44\xe3\x69\x4c\x2d\x31\x93\xfe\x06\xf0\x20\xe9\x1e\x90\x6b\x09\xc9\xde\x76\x77\xa4\x83\x1b\x0d\x97\xd2\xb2\xd9\xd2\xe7\x34\x18\x92\x0d\x99\x2a\xea\x67\x94\x06\xa9\x6f\x9e\x9d\x8e\x94\x82\x4c\x34\x8c\xea\x46\x62\xed\x84\x28\x3c\xf5\x51\x57\x35\xa3\x70\x53\x3b\x66\xe2\xc8\x2e\x03\x5f\x1c\x51\xe0\xfb\x81\xf6\xf9\x3e\xf0\xc4\xfe\x4d\xe6\x06\x03\xa9\x6e\x89\xef\xbc\x9f\x95\x9c\xea\x72\xfd\x96\xe5\x38\x8c\xbf\x01\x09\x33\xbe\x42\x5f\x87\x18\xad\x1e\x7c\xcb\x5b\x67\x4c\x66\xc2\xa6\x3e\x97\x17\xd3\x29\xb1\x7f\xd8\xfd\x8c\x76\xec\xac\x31\xc6\x64\xa3\xe1\x89\x11\x9f\x4c\xec\x8f\xa4\xbb\xa1\x89\x70\x37\x2c\x84\xe5\x5a\x39\xca\xd1\xae\xc0\x7b\x7e\x2d\xf3\x42\x1a\x12\xb8\x55\x84\xdb\x51\xb2\x05\xf1\xfb\x6c\xd9\x2d\x70\x43\xcf\xf3\xfd\xea\x5c\x5f\x74\xec\x07\x93\x5d\xd9\xf4\xd6\xbc\xa6\x09\xca\xd7\xed\xf4\xbc\xee\x6e\x23\xd3\x00\xe4\x9e\xca\xb6\x84\x7f\x85\x0e\xb1\x57\x4c\xf9\xd7\x84\xd2\x54\xd7\xdd\x2a\x17\xfb\xac\x7c\xa1\x25\x37\xf2\x4c\xfe\x42\x96\xc1\x79\x1f\x46\x7d\xf2\x18\x8b\x95\xd4\xd3\xca\xbf\x42\x49\x72\xd8\xb1\x59\xd2\xdf\xe8\xd0\x25\x53\x46\xd2\x4d\xd8\x79\x02\xd2\x1f\x5e\x04\x99\xe9\xdd\xb2\xe7\x92\x49\xff\x2a\xb5\x58\xdc\x0f\x83\x04\xc6\x81\xce\xb4\x4e\x44\xb0\x6b\x4d\x24\x58\x51\x5d\x8e\xae\x7f\xc8\x1b\xa9\xcc\x0f\xcb\xd2\xfc\xd0\xb2\xcf\x38\x88\x59\xd4\x27\xdb\x65\xac\x2f\x35\xb1\x72\xec\x25\x51\xfe\x80\x82\x06\xe5\xf7\x28\x88\x8e\x9b\x40\xe5\xf7\xbb\x79\xb7\x0e\x47\xd2\xb2\x58\xef\x4f\x89\xf2\xfb\x80\x76\xb9\xc5\x3c\xb4\xd6\x75\x5e\xa9\x46\xc3\xe3\x76\x0f\xf9\xa2\xd1\x10\x3e\xef\xf5\x0e\x2d\x22\xc7\xd1\xc4\x48\x25\x35\xf1\xc4\x28\x12\x57\x1e\xbc\x52\x44\x50\x0a\x16\x85\xb4\xe5\x4e\xd9\x02\x22\x21\x66\xad\x4e\xbc\x17\x65\xac\x6c\xdc\x6c\xd2\x6f\x8a\x08\xb8\xd6\xa4\x6d\x3b\xd1\x8d\xce\xe3\x8b\xc0\x7e\xa0\x35\x23\x67\x70\x45\x49\x35\xab\x97\xac\x03\x56\xf8\x33\x65\x6f\x9d\x8e\x25\x53\x76\x22\xba\x03\x5b\x3a\xa1\x41\xba\xbf\x65\xf7\xce\x55\xc7\x24\xb7\x78\xbb\xe3\xbc\xcc\x63\x97\x70\x9b\x26\x10\xef\x86\x8f\x12\x89\x5b\x60\x3a\xf5\xc4\xa5\x14\x57\xc8\xad\xda\x9f\xea\x5c\x5e\xac\x33\x96\xd0\x46\x03\x75\xbc\x2c\x29\x2b\x90\x07\x0b\x8b\x70\x62\xee\x46\xb2\xd6\x2b\xb8\xe4\xb5\xaf\x17\xd8\x30\x57\xb2\xe4\x0c\xd3\x91\x5d\xe5\x4f\xa4\xd9\x37\x46\x47\x61\x62\x24\x71\xb7\xa9\x7c\x2d\xaf\xe3\x1b\x59\x4a\x2e\xe3\x73\xfb\x20\x5c\xb0\xcc\x72\x1f\x38\x93\x7e\xdc\xe1\x0b\x6d\xbc\x3f\x25\x09\x18\xbc\x34\xb5\xd8\x8e\xcb\x2a\xb7\x75\xb7\xb8\x5f\xed\xd2\x7d\x39\xc1\xfd\x86\xdf\x90\x76\xcc\x89\xee\x66\xc1\xed\xcb\x8a\xe5\x76\xa3\x71\x54\xda\x09\xf7\xe9\xff\xf4\x37\x18\x63\x1c\x85\x70\xff\x27\xe3\x1d\x11\x2b\x13\xa9\x44\xce\x32\xac\xe6\x97\x65\x62\xf9\x03\xc1\x7e\x59\x52\xc3\x29\xa8\xe5\x85\x9b\x80\x80\x89\x6e\x34\xee\xc7\x7c\x32\x89\x6e\x64\x30\x90\x84\xd3\xbd\x2d\xcb\x03\x59\x92\x24\x9c\x0e\xb0\x1e\xbc\x2b\x96\xf1\x96\x46\xdf\xdd\xdf\x46\xaa\x17\xdf\x56\xec\x11\xe3\x39\xdd\xfd\x09\xd2\x05\xdf\xc9\x3e\xb9\x19\xf2\x7e\x06\x5e\x8a\x84\x07\xf7\x03\x69\x82\x12\xdf\x30\xd1\x6c\xbd\x65\xcf\xe6\xc2\x51\xa2\x18\xee\x5f\x9a\x84\x60\x69\x7c\x49\xa7\x96\x0b\xb5\xfe\x4f\x30\x6c\x84\x67\x0a\xa8\xcc\x9c\x67\x68\x69\xf3\xb8\x13\x4e\x53\xa4\xfa\x1c\x04\x4b\xba\xf6\x5c\xe3\x3e\x0f\xb8\x2f\x8e\x02\x0e\x11\x6b\x5b\x8a\xcd\xfd\x30\xd8\x66\x2c\x69\x34\xb8\x3d\x6c\x62\x46\xa2\x46\xc3\xae\xec\x78\x6c\x7b\xc1\x07\xdc\x61\x0b\x64\x6b\xa9\xb8\xdd\x25\xca\x1f\x6b\xa4\x5f\x2f\x64\x9f\x27\x23\x43\x28\x84\xb4\x23\x59\xec\x0f\x3b\xce\xe7\x7d\xf9\xb2\x87\xa4\x82\x49\x22\x68\x07\xa7\x21\xc3\xb9\xcf\x64\x6e\x3d\xdd\xdc\xec\xd8\x32\xe7\xfd\x0b\x5b\x2c\x66\xb1\x3f\x9e\xc5\x04\x19\xb7\xec\x28\x99\xf8\x3f\x99\x82\x49\x31\x62\x87\x73\x9b\xf3\x3c\x77\xca\xdf\x4f\x17\x2e\xb4\x68\xf9\xfe\xf6\x95\x5e\x94\x2a\xef\x37\x02\x0d\x3a\x30\x30\x09\x24\x98\x54\xb4\x80\x24\x93\x31\x72\x4d\x4e\x26\x19\x41\xe9\x06\xcd\xbe\x9e\xbb\x42\x83\x5e\xaa\x19\x5c\x65\xb9\x0b\xcb\x84\xa0\x7f\xdb\x3a\x63\x6e\xfd\xb7\x2d\x9d\x99\x4e\xb7\x30\xa1\xac\x8e\xb9\xd2\xc4\x40\x0b\x24\x1a\x7e\x59\xb5\xa2\xc9\x92\xdd\x3f\xbc\x0a\x66\x4f\xe1\xfc\x42\x5f\x2a\x5c\x2a\xdf\xca\x6e\xca\xef\x81\x0c\x24\xf4\x03\x7b\x54\x84\x81\xf2\xc3\xd9\xcc\x2d\x9a\xf6\x2c\x55\x8e\xf1\x54\x35\xb6\x53\xd2\x32\x29\x7f\x04\x91\x6d\x1c\x62\x26\x72\xdb\x29\x8b\x19\x63\xf9\x21\xd0\x6f\x34\x62\x3b\x8b\x7d\x26\xce\xe3\x0b\x9b\x73\x1e\xe3\xe6\xef\x2f\x68\xfb\xed\x59\x7d\x45\x3b\xf6\x8b\xb6\x87\x76\xc7\x59\xb0\xe7\xe7\xcf\xbf\x02\xed\x5f\x41\x68\xe7\x10\xeb\xb5\xf6\xc2\xdc\xe3\x0e\xc7\xab\x0d\x12\x42\x9a\x3b\xcb\x64\xc8\x4e\xec\xf1\x0d\x23\xa6\xfd\x21\xdc\xb0\xf5\x36\xf4\x6c\x73\x78\x9e\xf7\xec\x79\x7e\xc3\xd6\x5b\xb0\x74\xa8\x4f\xba\x13\x76\x3e\x81\x9e\x3d\xd4\x27\x6e\xba\x7b\xf6\x50\xef\xb1\x9e\x7f\x95\xd3\xb8\x0d\xa6\x53\x50\x1b\xf5\xa0\x46\xdd\x11\x3b\x1f\xc1\x86\x05\x35\x72\xa0\x36\x2c\xa8\x0d\xb6\xe1\x5f\xe5\xca\xc0\x46\x63\x92\x76\x67\x9d\xb1\x51\xfa\xb5\xbb\xb8\x1a\x02\x42\x6e\xba\x75\x82\x7d\xab\x63\xf6\x8a\x6b\x19\xce\x52\xa9\xce\x8d\x3d\xcd\xd0\xfb\x64\xd9\x4c\x49\x26\x30\xa2\xc1\x84\x31\x36\xa2\xd3\x29\xb6\xb3\x05\x12\x46\x6e\x88\xed\xb8\x5b\x69\xc7\x80\x6c\xb6\x97\xec\xfb\x38\x09\xca\xe7\x68\x37\xe5\xe9\x1c\x6c\xa3\xc2\x9b\x2f\xbb\x0b\x58\x70\xa7\xf9\x0e\x81\x83\x45\xbf\xaa\xa5\x12\x47\x59\x89\xed\x00\xed\xe3\x97\xd8\xce\x65\xed\x36\xb1\x43\x70\xcd\x86\x76\xa5\xf4\x40\x5b\x0e\xe5\x3a\xc5\xe9\x31\x48\xb8\x76\x05\x2e\x99\xf6\xa3\xc2\xb0\x5c\xee\x49\xb6\x8a\x76\x40\xc2\x25\xa5\x65\x5d\x77\x09\xab\xc4\xed\xed\xcc\x6a\x6e\x89\x5f\x6a\xb2\xce\x0e\xba\x32\x06\xbc\x84\x01\xb7\x82\x72\x2e\xdf\x23\xd9\x2b\xa1\x5f\xba\x94\x3d\x7f\xc8\x5a\x7e\x7b\xde\xdb\x05\xaf\xbd\x59\x3e\x68\x9d\x31\x61\xf9\xb7\x56\xfe\x6d\x3b\xff\xf6\x18\xbf\xd9\x92\xa2\xc4\x10\x44\x4c\x9d\x8b\x0b\x88\xdd\x05\xc9\x88\x31\x16\x37\x1a\x05\x2f\x64\x6b\x96\x78\x21\x31\x9d\xa6\xdc\x95\x69\x34\x08\x49\x58\x44\xed\x39\x4d\x38\x8b\xa9\xbf\x81\xc6\xf7\xfc\xd2\xc7\x74\x4a\x88\xb4\xdc\xd3\xfd\x8c\x9e\x8b\x0b\x16\xbb\x2e\xce\xa5\x99\x6e\xca\xbd\x99\xae\xe7\x65\x8c\x9b\xb1\x8d\x6c\xbb\x54\x47\x65\x51\xf8\x3b\x17\x17\x7e\x1f\xe2\x8c\xf0\x06\xcb\xd7\xa6\xce\xc5\x85\x05\x63\x4f\x5e\x3c\x44\xee\xdd\x01\x62\x87\xcf\xf6\xd1\xf6\xd0\xb6\x0c\x82\x5a\x42\x34\x8f\x5d\x9f\xce\x72\x47\x19\x37\x3c\xf8\x47\xcd\xf5\x22\xb4\x74\x33\x2c\x5f\xa0\x2d\xae\xc1\x2f\x1d\x1c\x96\x18\x5b\x02\x2f\xed\x39\x9b\xd1\xc3\x88\xf1\xdc\xc1\x60\x4f\x74\x71\xba\x77\x41\xc2\xfd\x4d\x10\x41\x14\x88\xcd\x68\x46\x03\xb1\x17\xa5\xab\xe4\x89\xcb\x12\x20\x03\x5e\xe2\xa3\x62\x26\xf6\xa2\xae\x08\xa2\xcc\xc1\xc8\x79\x16\x39\x1a\x99\x9c\xf7\x2f\x3a\xfb\x96\x51\xe0\xe7\xfd\x0b\x30\xd0\x6c\x3a\xb7\x5f\xa7\xc3\x2b\x2d\xe2\x23\x5d\x7d\xd5\x09\x38\xb3\xa3\x64\xbf\x65\xac\xbc\xed\x46\x3f\xa7\xe3\x10\xb2\xcc\xa7\x09\x26\xac\x05\x23\xd6\x82\x1b\x26\x3b\x93\xbd\x7e\xa3\x31\xda\x0b\x53\x83\x71\x8f\x91\x53\x16\x9d\x4f\x2e\xa8\xcf\x61\x83\x91\x21\x8b\xcf\x47\xf8\xe3\x9a\x9d\xfa\x21\x5c\xb2\xa1\x1f\x22\x9f\xb2\xce\xd8\x86\xab\x33\xb0\x15\x9a\xed\x0b\x18\xdb\xc2\xcd\x36\x9e\x0e\x03\x6a\xb3\x6e\xd9\xc0\xe7\x70\xc7\x06\x7e\x08\xbf\x98\x65\x0f\x6f\x6d\xe6\x18\x33\x0f\xd9\xd8\xe7\x70\xc5\xc6\x7e\x08\xfb\xac\xc7\x18\x3b\xb4\x99\xfb\x8d\xc6\x2f\xba\xaf\xc9\x35\x5c\x41\x02\xcd\xe6\x0d\x85\x1f\x1a\xe3\x6d\xf4\xe0\x12\x46\x96\xab\xbb\x69\xb2\x6b\xa7\xdd\xfc\x98\xe5\xdc\xb9\x92\x37\x4d\x76\xe7\x72\x26\x4d\xb6\x05\xa3\x26\xdb\x72\xcc\x89\x05\x4c\x6f\x9a\xcd\x0c\xd6\x46\x06\x2b\x6f\xe9\xa6\x0c\x77\xd2\x64\xed\xf9\xda\xbf\x68\xde\xd6\x75\xde\x56\x5a\x7a\x5f\x93\x3b\xb8\xcc\xb0\x5d\xc6\xa1\xdd\xc9\xcc\xe4\xeb\x83\xe9\xf4\x76\x9d\xb1\x43\x1a\x6a\xc9\xaf\x3a\x8b\x30\x17\xb1\x5b\x68\xe3\xaa\xbe\x8d\xad\x99\x23\x47\xd8\x9f\x32\x2e\x79\x8f\x9a\x30\x6a\x36\x71\xcb\xd8\x59\x4f\x27\xfc\x34\x43\xa1\x34\xef\x6e\xaa\x97\xeb\xbb\xba\xc5\x62\x19\xc2\x01\x3b\x98\x4e\xcf\x2f\x3a\x29\xda\xa5\xe5\x32\xf4\x43\x48\x19\xaf\x03\x8a\x0d\x93\xd6\x5e\xb6\xa7\xa6\xd3\xd6\x9e\xc8\xbf\x1f\xd0\x74\xeb\x3c\xb5\x5b\xe7\x36\x48\xe0\x57\x20\xe0\x2e\x38\x48\x2d\x57\x27\x9a\x79\x3f\xe4\xe8\xfa\xcb\xee\xf3\xe3\x52\x78\x9f\x1f\xba\xca\xe0\x6e\x4f\x4a\x74\x5f\x10\xd9\x19\x93\x9a\x58\xee\x75\x90\xc0\x7e\x20\xd8\xbd\x08\x5a\xf0\x3b\x90\x60\x13\x26\xb9\xe2\x39\xe5\x47\x6c\x7d\x26\x90\x15\xb7\x22\xaf\xf0\x45\x6e\xa4\xc9\x20\xcc\x28\x08\x5f\xb0\xad\xd4\x66\x3f\xc7\xe0\x08\xff\x37\x48\x88\x40\xf8\xda\x96\xd2\x2c\x71\x60\x85\x3f\xf1\x27\xec\xfe\x36\x88\x1c\x84\x59\x86\x7d\xf3\x44\x67\x5a\xd8\xbc\x67\x1f\xe7\x4e\x2a\x77\x20\x65\xfd\xe2\xb9\x9f\x04\x77\xa8\x65\x88\x88\x79\x44\x24\x70\xff\x37\x08\x48\x52\x26\xe0\xca\x4a\x59\xcf\x20\xb1\x03\x2c\x60\xdf\xd2\xa6\xd9\xc7\x79\x1c\x1c\xb1\x4f\x8f\x98\xbc\x7c\x66\x00\xc0\x81\xb9\x17\x41\xbb\x34\x76\x51\xf9\x7c\xfd\x5a\x22\x4d\xeb\x25\x63\xfc\x82\xc2\xd7\x11\x43\x94\x20\x1d\xad\x8f\x7d\xed\x6e\x4c\xdb\x23\x98\x77\x32\x9a\x18\x3b\x36\xdb\x4e\x42\x48\xbf\x5a\x6c\x8c\x7f\x05\xb1\x3f\x81\x88\xe6\x9b\xf2\x29\xe6\xde\xc7\xbe\x61\x1a\x62\x3f\x61\x91\xd3\xe1\xb1\xd8\x9f\xf8\xb7\x9d\xd6\xde\x24\x67\x2e\x1d\x22\x13\x68\x65\x8a\xe3\x0c\xc6\xb3\x6a\x18\x23\x0b\xc3\x62\x30\xa2\xf7\x23\x7f\xdf\x9f\x30\x9d\xc2\x1e\x3d\x04\xd9\x81\x2e\x03\xb4\x0b\x92\xd8\x5e\x37\x9b\x68\x19\x26\xd8\x6d\xfa\xef\x7c\x91\x26\xb8\xd2\x6f\x98\x71\xbd\xb6\xbc\xe8\x4d\x41\xe1\x7b\xcc\x94\x79\x5d\xc7\xbd\x16\xe6\x0f\xe8\xb9\x01\x6e\xb6\x41\x80\xae\xd0\x44\xd1\xf4\xea\xbc\xf1\x65\xca\x61\x69\x5f\x5c\x46\xa3\xde\xfb\xb8\x27\x27\xf9\x19\x75\xc9\x5a\x9d\xcb\xbd\x8d\xec\xb4\xbb\xcc\x0e\xa8\x81\x95\x30\xd9\x4d\x77\xe3\xfc\xf2\x22\xb0\x1f\x7e\x08\x63\xd6\x6c\xf2\x26\x19\x38\x3b\x0f\xae\xcc\x3d\xd6\x6f\x34\xfa\x7b\x6c\x8c\xd1\x1e\x14\xb9\x3e\xbf\xbc\x80\x41\x3a\xf7\x63\x88\x28\xb8\x31\x58\x18\x81\x7c\x08\x3a\x9c\x8d\x67\xf9\x78\x64\xb2\x1e\xb4\x40\xfb\x21\x94\xc3\xd0\x9c\xe9\x25\x9b\x0c\x6a\x06\x33\x76\x5b\x05\xa4\xb4\x18\xe1\xbd\xfd\x6e\xca\x4e\x9c\xef\x75\x15\xd3\xad\xcb\x4c\xf7\xa2\xea\xc5\x00\x67\x9f\x34\x49\x30\x30\x03\x63\x4c\x61\x2c\x83\x42\x21\x5a\x72\xea\xfb\xa4\xe7\xee\x2c\xe8\x92\xeb\xe7\x92\x01\x76\x5e\x11\x53\x98\x3f\x21\x61\xd7\xb8\xe6\x69\x27\xa9\x98\xd0\xe9\x94\x54\x25\x3b\x5d\xce\xe2\xe4\x77\x64\xa3\x61\xa5\x55\xd5\x68\x2c\x98\x55\x13\x50\xa5\x28\x12\xe8\x3b\x30\x01\xed\x27\x0b\x57\x15\x52\xa5\x9e\x9f\xd8\x7c\x0a\x8b\xae\x07\x2a\x03\xfa\x82\x1b\x4e\x5a\x90\x09\x2f\x73\xa5\x73\x19\xc2\x8d\xbd\x3f\x59\x94\x1c\xaa\x50\xef\x56\x25\xfa\x43\xa6\xfd\x49\x50\x95\xc5\xee\x87\x81\xed\xc2\x38\xd0\x7e\x32\xcb\x9a\xde\x0d\xca\x97\xd8\x26\x69\xc4\x1c\xe3\x47\xe8\x07\x9a\x29\x8f\xdc\x88\xa8\xd2\xbe\x38\x37\xfe\x4d\xc1\x38\xaa\xcc\xb7\xb6\x60\xbb\x08\xc2\xa3\xc8\x34\xce\x55\x94\xcc\x56\xed\xc8\xfc\xc0\x4b\x5b\x8a\xd4\x44\x6a\xf3\x5c\xf6\x63\x2d\xc9\xb5\x26\x09\x3a\x9f\xfa\x09\x05\xbe\xd8\xce\xb3\x00\x69\x86\x6b\x81\x16\x1a\x8b\xb2\x81\xbc\x84\xb6\x1d\x67\x77\x0a\x18\x7f\xbf\x2c\x11\xad\xb5\xac\x0c\xe0\x6b\x54\xf0\xd4\x56\x16\xfe\x84\xb9\x6d\xe2\xdf\xe6\x53\xf6\xb4\x6a\xb9\xe6\xf7\x90\x71\x20\xe7\x73\x30\xee\x41\xe6\xb4\x57\x8c\x79\xae\xb5\x7e\x91\x7a\x0d\xbc\xd4\x7c\x80\xea\xeb\x3c\x7a\x51\x79\x98\x32\x5e\xdc\x5d\xeb\x4c\xfc\xfd\xce\x37\x65\x25\x5a\x77\xe4\x75\xb9\x3f\x09\xae\x35\xb1\xa7\x9b\x1d\xb9\xb2\xef\x9a\xf1\xef\x5c\x78\x85\xbc\x2b\x85\x1a\x93\x19\xff\x57\xea\x92\x9e\x4f\x4a\xc9\x33\x3d\x39\xe7\x96\x73\x16\xfe\x3e\xc4\x6c\x0b\xf5\x1f\xa2\x1b\xb9\xa6\xa2\xb4\xa9\xce\xc2\x04\xc6\x30\x37\xe9\xc2\xd7\x17\x74\x26\x1b\x0d\xf4\x83\x90\x25\x87\x21\x17\x1f\x63\xfe\x1e\x8d\xf6\x27\x44\xd1\x4e\xcf\x29\xdb\x82\x1b\xd2\x6e\x95\x95\xb4\xc7\x3a\x75\x0a\x75\x91\xb9\xec\x02\x3f\xbb\x1b\xcb\x6c\x21\xbc\x55\x44\xf9\x46\xfe\x32\x07\xb1\x32\x52\xb9\x1b\x97\xed\xf5\x9a\xa2\x9e\x57\x0c\x44\x16\xf6\x81\x67\x0a\xe2\x09\xac\xb8\x57\xdb\xd1\xec\x3d\x19\x92\xbe\x86\xc4\x57\xfc\x5a\x42\xe2\xa3\x9c\x89\x97\x66\x53\xc6\xc4\x37\x7c\xf0\x9e\x5f\x4b\xdf\xc4\xc7\xf1\xad\xd4\x07\x7c\x22\x09\x05\xc1\xce\x50\x14\x59\x38\x67\x64\xa1\x59\x92\x4e\x39\xf8\x9e\x1c\x6b\x12\x9d\xcb\x0b\x6a\xa5\xbc\xc2\x88\xae\x81\x83\x06\x31\xe7\x3e\xa2\x41\x81\x29\x99\x8d\xd1\xe9\x32\x02\xed\x8b\x7d\xfb\xb1\x63\x3f\x4a\x6e\x9b\x18\x5c\x20\x73\x8b\x10\x4f\x80\xb3\x08\xc7\x07\x04\x3b\xd6\xa4\xd8\x73\xbf\xe7\xdc\x4b\x72\xf5\x6c\x82\xa1\x0b\xd8\x21\xda\x4b\x68\x87\xb3\x33\xcb\xe6\x0a\x77\xaa\x08\x86\x2e\x78\xa9\xd5\xf0\xc5\x9c\xc7\x80\x43\x53\xce\xa3\x29\x6b\xd1\x4c\x32\x34\xad\xec\xc9\x6f\x1b\x0d\xfb\x49\x30\x24\x12\xa2\x1d\xd9\x2d\x64\x22\x33\xb2\x62\xdd\x67\xe5\x87\x71\xef\x0e\xfa\xb6\x0b\x71\x7d\x17\x5e\x29\xc6\x3b\xae\x1f\xc2\xf5\x43\x69\xe2\xd9\xaa\x1e\x25\x67\x94\x68\x3f\x7c\x6a\xf7\xdf\xa1\x26\x7d\x7b\xcc\xc4\xb6\x77\x31\xf4\x91\x13\x84\x3e\x33\xf0\x4a\xb1\x16\x44\xa8\xb0\x11\x5b\x8d\x06\xc9\x90\x60\x11\xa6\x50\xd7\x7d\xf8\xa2\x2b\x7d\x85\xb4\xfc\x99\xc8\x89\xd9\x57\xd1\x35\x6a\x9e\x5f\x6a\x7e\x2d\xbb\x95\xa9\x73\xee\x4e\x25\x47\x2f\x05\x6d\xb9\xfd\x68\xb7\x45\x4b\x4e\x46\xbf\x35\x1a\x54\xee\x25\x31\xa9\xc7\x47\xd9\x6b\x9c\x13\x7a\x9f\x20\xb7\x92\x74\x5b\x01\xf9\x62\x27\x19\xd0\xf8\xdb\xce\x09\xc5\xc2\xcd\x47\xa6\x40\x77\x09\x96\xb1\xfb\xde\x85\xaa\x6a\x53\x1a\x20\x93\x9d\x34\x1a\x0e\x48\xc2\xb6\xca\xfb\xf3\x8d\x2e\xfc\x05\xde\x4b\x3b\x34\xa3\x58\x60\x8f\xfc\x4b\x7b\xe6\xfa\x7c\x3a\xbd\x21\x6d\x3a\xab\x75\xe7\x14\x09\x7c\x92\x73\xbe\x6e\xf4\x5e\x37\x1a\x97\xd1\xc4\xc4\xfa\xce\x1f\xc4\x78\x9b\x80\xb8\xa8\x19\xd8\xd3\xef\xb5\x66\xe9\x6a\x68\x19\x28\x2b\xbc\x9c\x1a\x6e\x24\x5a\x31\x3c\x28\xc1\x85\xd7\xba\x36\x9a\xc5\x6a\xa0\xe9\x91\x5f\x07\xf7\x7e\xd1\xc0\x52\xb6\x97\xcc\xa0\xc2\x5e\x13\xcc\xbb\x56\xc3\x07\xcd\xc8\x2a\x1f\xb4\x46\x23\xfb\x06\x55\xc5\x9c\x9d\xa7\xeb\xfe\x04\xaf\xf5\x9c\xcf\xc2\x3c\xef\x78\xa2\xc8\x7c\x1f\x4b\xc2\x8b\xa2\xf7\x47\x8a\x48\xf4\x8d\xcb\x29\xf7\x92\xf1\xc8\x80\x9a\xb7\x53\xe1\x2d\xf6\xf2\xc4\x56\x5a\xa8\x8c\x8b\x1f\x5b\x1f\x59\x29\xbd\xfd\x5a\xba\x35\x66\x68\xf7\xd6\x10\xe3\x73\x1a\xdc\x99\xb2\x23\xc1\xcf\x74\x5f\x54\x38\x1a\x6b\x7a\xff\x45\x97\xfb\xe7\x6e\x06\x64\xc3\xe7\x0f\xa4\x49\xed\xc9\xcf\xef\x8e\x7a\x76\x5f\x69\xa2\xba\x87\x69\xb7\x83\x2b\x45\x6e\xd1\x28\xe5\x36\xbc\xad\xfc\x4e\xcf\x3b\x38\x17\x7e\x84\x3f\x17\xc9\x50\x76\x08\x9e\xeb\x0b\x42\xe1\x6a\x95\x8b\xb3\x61\xcb\xbe\x38\x1f\xb4\x3f\x11\x3a\x1e\xa1\x5f\x91\xad\xbf\xe8\x1d\x3a\xdf\x33\xf4\x07\x35\x84\x96\xee\x5c\x98\x15\xee\x2a\xf5\xe8\xa6\xad\x1e\xcb\xbe\x15\xe2\xb2\x9f\x67\xf1\x98\x99\xb4\x13\x16\xf6\x73\xcd\x1e\x8a\x0d\x94\x33\xc3\x82\xe9\x26\xdf\x2b\xab\x15\x5b\x1d\xd1\x68\x44\x7b\x99\xc8\x1b\xb3\xa4\x1c\x45\xc1\x72\x0c\x4c\x9d\x47\xcd\xe6\x85\xa5\x43\xe7\xba\xd9\xbc\x68\x34\x48\xdb\x52\xa5\xb8\x4b\x4c\xb3\x09\x92\xb5\x69\x40\x64\xb3\x09\x18\x71\x83\x31\xb2\xbb\xfd\xf8\xe9\xd3\x46\x4c\xbb\x0b\x15\x83\x76\xb1\x7e\xf7\x89\xe8\xea\x60\xb3\x9d\xba\xa8\xc1\xcb\x15\x2e\x73\x3a\xf7\x6b\xed\xce\x37\x61\xe6\x51\xa5\x5d\x45\x4e\x89\xf1\x27\x49\x38\x31\x56\x6e\xd9\xa2\x94\x76\x75\x73\x2b\xd8\x6c\x07\x98\x75\xae\x2f\x28\xed\x7a\xff\x28\x54\x12\x9f\xeb\x8b\xee\xe6\x56\xa0\x9b\x6d\x5b\x60\xb3\x3d\xa3\xf0\xb7\x5e\x15\x2d\x63\xae\x35\xcb\x12\xcd\x28\xbc\xd2\x95\xd1\x2a\x3a\xaa\x90\xe4\x54\xc6\xe1\x99\xf9\x10\x15\xce\xd6\x6a\xf6\x1e\x3f\x9d\x4e\x77\x9e\x14\x41\xf2\x54\x21\xce\x51\xf8\xac\x57\x06\x23\x69\x75\x8a\xd1\xe9\xe8\x82\x71\x5d\x40\x76\xf3\xf1\x53\x17\x0e\xa3\x35\x9d\xaa\x3d\x96\xa4\x8a\x3f\xc9\xd4\x5f\xb2\x99\xcc\x72\xc7\x22\xed\x66\xe3\x9b\x5e\x11\x82\xa3\x55\xd9\x37\x59\xd5\xb7\xc7\x4f\xff\x2d\xa7\x53\xf9\xef\x9d\x27\x34\xea\x93\xdd\x1d\xf7\xeb\x49\x0b\x99\x4a\xb9\xf7\xec\xc9\x74\xda\x6e\x6d\xed\xc9\x14\x1d\xc3\xda\xbb\x7f\x99\xa6\xdc\x7c\xfa\xc4\x69\x2f\xf2\x84\x9d\x9d\xce\x7c\xc2\xe3\xa7\x05\xd2\x0a\x3d\x26\x3b\x0f\x6d\x82\xa4\x14\xdb\x42\x5b\xb6\x86\xef\xb5\xba\xd9\x4e\x08\x78\x33\xe7\xff\xf5\x9e\xe8\x64\x46\x8e\xf9\xdd\xd0\x6c\xd2\x0e\xae\xfd\xa8\x4b\x24\x6b\x83\x71\x61\x78\x96\xd6\x7e\x44\x1b\x0d\x5b\xb8\x58\xed\x3c\x5d\xe8\x2e\xc0\xc9\xdc\xf0\x96\xdd\x30\x17\x28\xa6\xa3\x91\x4a\xde\xae\x7d\x7d\x77\xfc\xda\x98\xf1\x47\xc7\xb9\x74\xd6\x97\x65\x9e\xe3\xa8\xb8\xed\xdc\xa9\x70\x63\xf0\xc6\x3a\x1e\x68\x39\x99\x78\x73\xb4\x26\xeb\xf5\x41\x7c\x3d\x4e\x0c\x0f\x47\xb2\xd1\x38\x42\x5f\x00\x72\x2f\x78\x60\x59\x0a\xde\x93\x3d\x10\x61\xa0\x7c\x13\x1b\x3e\xc2\xb3\x62\x86\xde\x2f\x55\xee\x12\x9e\xd4\x3a\xd6\xde\xdc\xc1\x43\xae\x14\x79\x1f\xe1\x19\x53\x55\xc3\x38\x56\x6b\xb9\xce\xa7\xfa\x3a\x16\xad\x85\x0a\x55\x87\x17\x91\x4c\xc1\xbd\xd8\x0d\xac\xb4\x39\x19\xc7\x6a\x22\x3f\x7d\x3c\x86\xf0\x43\x70\x2f\xfa\x81\xf4\x27\x86\x9b\x64\x02\xe2\x28\xff\x7e\x26\x7f\x99\x19\x88\xdb\x0a\xf7\xf7\x5e\xd2\x29\x4b\x97\x6b\xba\x24\x5f\xaa\x34\x30\x8f\xf7\x8f\xfe\x47\x79\x14\x56\xc7\x09\x2a\xd6\xa2\x17\xac\x79\xce\xad\x6c\x2f\x57\x1f\x27\x29\x09\x8b\xd4\x80\xb4\x80\x53\x88\xe6\x92\x78\x73\x8b\x76\x34\x3b\x20\xcf\xa3\x72\xdc\xf1\xe2\xe0\xb8\x35\xe4\x38\x22\x8a\x76\xa3\xa6\x07\x18\x06\x83\x07\x11\x9d\x59\x71\xa9\x70\x9d\x23\xd2\x9e\xb9\xfb\xa3\xd1\xc7\x74\x5c\x5e\x4b\xde\x93\x7a\x42\x28\x85\xf0\x69\x69\xbc\xd2\x45\x2b\xdd\xdd\x62\x37\x48\x7b\x5b\xad\xd6\x74\xba\xdd\x6a\xed\xb1\x2c\x89\xe6\x64\xd2\xb2\xf7\x4c\xe5\xf5\xed\x80\xc2\x95\x22\x5f\x23\x7b\x7e\xa7\xec\xb2\x26\xa6\xcc\x51\x24\xd4\x1e\xf5\x89\xe5\x28\x48\x2d\x80\x21\xf9\x18\x61\x6c\x38\x64\x03\xac\x30\xe3\x8b\xb1\xcf\x91\x35\x35\xfa\xee\x5e\xf9\xf1\x58\x2a\x22\x7d\xf1\xc6\x66\xed\xc2\x7a\x6b\x39\x6a\x08\xae\xab\xb3\xc8\x96\xda\xb5\x60\xd6\xeb\x23\x0d\x89\xdb\x8e\xf1\xc3\x8e\x0b\x06\x88\xbe\x4e\xe9\xf6\x73\x23\x65\x19\x20\x17\xb4\xce\x0f\xad\x58\x9e\xa3\x7b\x37\x46\x62\x38\xf6\x43\x50\xfe\x6d\x64\x2e\x0f\xb4\xec\x49\x65\x22\x3e\x9a\xd8\x8c\x67\x60\xf7\xaa\x2f\xda\xe8\x16\xe6\xa7\xab\xdf\xe6\xb4\x7d\xee\x3a\x96\x72\x0d\x4c\xfa\xe1\xd3\xc2\x53\x64\x22\x55\x8f\xbc\xb0\xc3\xd8\x25\x15\xf8\x78\xa9\x1c\xbe\x69\x31\xf0\x30\x5e\x21\x58\xd4\x03\xfc\x56\x66\x50\x7c\x1e\xc6\xda\x10\x3a\x5b\xe4\x84\x4a\xdc\x1b\xde\x5e\x08\x03\xe9\x87\xc0\x2b\xf6\x82\xf4\x79\xe9\x3e\xd2\x90\x7c\x89\x00\x03\x3a\x67\x97\x37\x94\xa9\x09\x49\xe4\x0d\xbc\x8e\xf2\xc5\x71\xa3\x41\x4c\x93\x79\xd7\x9e\xdd\xdf\x42\xa4\x3f\x23\xcf\xcd\x65\xb1\x92\x3f\xca\xc1\xe1\xaf\x31\x6a\x21\x97\x67\xf3\xce\x58\x2e\x5d\x9b\xfa\x68\x78\xc9\x68\x84\xc2\xe3\x75\x5a\x73\x75\xe8\x62\x48\xcd\x98\x2d\x10\xcc\x38\xaf\x94\x2c\xfc\x12\xc4\x6c\xb3\xdd\xe1\xcd\xe6\x9e\x6a\x34\xd0\xdb\x57\xfe\x92\x82\x08\x4a\x1b\x8d\x78\xbd\x5c\xb2\x53\x00\x2c\xbc\x90\x36\xdb\x10\xa6\x6e\x35\x7d\xda\x69\xe5\xa6\xaf\x09\xfa\x25\x75\xc2\xf3\xcd\xcd\xfe\x05\x9b\x58\xc6\x7a\x82\x6c\x75\x92\x45\x68\x7c\x17\x83\x3c\x6f\x5d\x80\x74\x34\x03\x38\x1c\x63\x14\x05\xb4\xae\xe6\x8d\x16\x82\x41\x9e\xc4\x22\x48\x63\x47\x96\xb4\x02\x09\x28\xe0\xd9\x6c\x08\xcb\x3f\x64\xf5\x52\x61\x6a\x81\x17\x8d\xfa\x44\x34\x9b\xff\x2e\x42\x80\xa8\x92\x16\x87\xeb\x01\x72\xef\x99\x19\x62\x73\x1b\xb2\xa0\xe0\xda\x76\x52\xe7\x21\xba\xf2\x92\xe7\xfa\xa2\x63\xce\x37\x37\xd1\x33\xf7\xd6\x10\x89\x9d\xcd\x5f\x5c\xc0\xee\x2a\x28\x8a\x2f\x35\xb1\x75\x01\x02\x8e\x73\x51\x80\x82\x31\xab\xc3\xb5\x65\x73\x5a\x9e\x4b\x31\x37\x5f\x2a\x27\xd0\x51\x36\xad\xd2\x05\x87\x88\x52\xce\x24\xf7\xc5\x75\x97\x9f\x38\x44\x6e\x32\x28\x9d\x07\x3c\x2b\x2e\x11\xcd\x95\xa7\x14\xca\x13\x23\xd2\x89\xa9\x0f\x69\xb8\x32\xa2\xe1\xaa\xcc\xff\xbe\x22\x56\xa1\xde\xdb\x53\x2b\xc2\x54\xff\xfb\xdf\xab\x73\x6d\x76\xe7\x0f\xee\x94\x66\x7c\xcb\x44\x9a\x23\x65\xa4\xbe\xe1\xa3\x72\xe6\x91\x22\x06\x0f\xa3\xba\xbb\x72\x79\x25\x95\x12\x28\x9c\x48\x03\x89\x61\x9f\x80\x1b\x36\x01\x61\x18\xb9\x9c\x0b\x06\x5a\xdc\xdd\xd5\xbe\xc0\x58\x70\x3d\xe0\x75\x9a\x8a\x03\xc2\x0d\x28\x7f\xa3\x6b\x02\x8e\x3e\xc8\xdc\xb6\x52\xce\xe4\x80\x7f\x2c\xe0\x84\x3a\x9e\xb8\x7a\x8d\x75\x9c\x5b\xe2\xe6\x16\x9a\x7e\x36\xe6\xa3\xed\x5a\x1e\xa0\x07\x09\x53\xc0\xd9\x01\x2a\x83\x43\x30\xbe\x80\x03\x22\x10\x65\x30\xbe\xc4\x50\xcc\x09\x68\xc6\xc1\x30\xe9\xee\x56\x18\x56\x71\xa8\x63\xa5\x5a\xe1\x64\x48\x12\x03\x2e\xac\x31\x72\xc3\x70\x66\xc5\x7a\x88\xe7\x41\xe1\xae\xcd\x77\x3c\x53\xf0\x07\x40\x55\x06\x4f\xd3\x19\xf4\x0d\x6b\x43\x68\xd8\x16\x4c\x0c\x6b\xc1\x68\x9e\xc8\x97\x82\x48\x50\xb8\xa9\xea\x45\x11\xe8\x01\x7a\x66\xd5\xdd\xde\x3c\x84\x30\x85\x8d\x15\x05\x5b\xe5\x82\xd7\x2b\x0a\xb6\xcb\x05\x2f\x6b\x50\x4b\x6f\xeb\xc1\xa0\x26\x7f\x2b\xcd\x1f\x1b\xf6\x06\x6e\x1f\x00\x72\x67\x98\x6d\x77\x06\xbf\x0c\x7b\x0b\x87\x86\x7d\x84\x2b\xc3\x06\x0a\xf6\x2b\xa7\x57\x35\x3d\x6f\x06\xa7\xa6\x5e\xbb\xf6\x19\x14\xbc\x70\xa1\xc9\x60\x58\x5b\xee\x98\x0c\xc9\x2b\xdc\x0f\xb6\xdc\x41\x65\x5b\x43\x72\x6a\xc0\xfb\x47\xad\xad\xad\xad\x79\x30\x24\x43\xfc\xe5\x81\xa2\x74\x06\x47\x75\xe4\x34\x5d\xea\xeb\x66\x31\xa8\xb4\xc4\xe8\xbe\x6e\x99\xe3\x03\x04\x59\x80\xe9\xf2\xb2\x86\x93\x9a\x55\x7d\x64\x6a\x49\x4e\xd3\x8a\xe4\x2d\x5c\xc8\x3f\x0c\xfb\x02\x1f\x1f\x40\xad\x9d\x45\x09\xcf\x79\xd1\x14\x3f\x65\x29\xc2\x66\x1b\xf1\x4b\x0c\xd6\xeb\x28\x26\x41\xb3\x04\x0c\xe3\x16\xbd\xaf\xa6\x9e\x5a\x7c\x74\xbb\xf5\x0c\xf7\xc1\x8a\x72\x3f\x6c\xb9\x21\xf9\x6a\xa0\x05\x27\x28\x76\xb7\xa9\x8b\x59\xfe\xbe\x62\x1f\xa2\x59\x22\x97\x2d\x5b\x45\xc8\xea\xf9\xd0\xa5\xba\xab\x83\x76\x6b\xeb\xf1\x5f\x44\x6f\x62\x06\x6d\xce\x55\x6c\xd3\x4d\x8c\x71\xd9\xdc\xdd\xd9\xd9\xde\x9d\xc1\xa7\xaa\xa6\xde\x9b\x12\xb3\xf6\xec\xc9\x1e\xc3\x68\x72\xac\xbd\xb5\x35\x83\xe3\x07\x2b\xe8\x3d\xf6\xac\xd5\x68\xec\xee\xec\x31\x3d\x83\x17\x7f\x52\x7e\xe7\x49\xa3\xf1\xf8\x29\x96\xff\x52\x39\xf1\x9f\x6c\x85\xe9\xf4\xd8\xfd\x79\x81\x11\x4d\xe1\x77\xfd\x1a\x49\x4c\x4a\xd2\xde\xfc\x27\x43\x69\x39\x8c\xa5\xf1\x3c\x21\xa7\x44\x9d\xb7\x2e\x2c\xe3\xe9\xce\xe7\x36\xa5\x41\x96\xda\x54\xe7\xed\x52\xd6\x16\xa5\xc8\xa1\xc0\xf7\xba\x89\xf7\xfe\x51\xff\x28\xe2\x35\xf7\x0d\x51\xcd\x36\x6d\x7a\x74\xcd\x6b\x1e\x18\xf2\x3a\x8d\x37\x0d\xaf\x6b\x36\xe1\x07\xbb\x5c\xce\xe8\x0c\x3e\x2c\x83\x56\x41\xba\xae\x2b\x42\x37\x65\x6e\x82\x1c\x6d\x68\x61\xd9\x02\x9a\x1d\xbd\x6f\x30\x10\x6e\xea\xb9\xa2\xca\xa1\xa0\x70\xbc\xa0\xb8\xcf\x95\xb9\x72\x93\x4f\x86\x68\x66\x25\x05\x9c\x14\x6d\xd9\xda\x21\xf9\x65\xe0\x0b\x2a\x2e\x08\xfa\xfe\x83\x70\x1b\x48\x76\x3d\xdf\x6b\x26\x81\x77\xfe\x2f\x0c\xf9\xf6\xaf\x0b\xcf\xed\x78\x0e\x9a\x89\xfc\xca\xc5\x5a\x6e\x76\x47\x44\x53\x57\x25\xef\xdc\x8d\x95\xcf\x69\xd3\xbb\xf0\x3a\x25\xb8\xd1\x2a\x28\x5b\x81\x53\x50\x2a\x9f\xdb\x9e\xc5\x7e\x88\x9b\x3e\xf6\xc3\xec\x96\x5a\x9f\x11\xed\x87\x5d\xef\xec\x52\xae\xbd\x99\xc4\xca\x7f\x21\x45\xdc\x93\x7e\xac\xe4\x49\x7f\x8d\x9b\xb5\xe1\x24\x56\x5e\xd3\x91\x3f\x0f\x7e\x63\x37\x03\x6f\xa9\xa8\x47\x9b\xde\x5a\x9f\x47\x23\x0c\x6c\xb7\x66\x2e\xe5\x5a\x3f\x1e\x8d\xe2\x5b\x17\x90\x6b\xdf\x90\x13\x43\x62\x6a\x4b\xdd\xf2\xbb\x49\xe0\x75\x16\x08\xab\x25\xa6\xd8\xa1\x3e\x0c\xc9\x99\x81\xef\x06\x62\xcb\xaf\x2a\xc6\x99\x61\x31\x3e\x8b\x23\x98\x2e\x75\x31\x65\x1c\xbd\x8f\x5c\xad\x45\xca\xc4\x6b\xbc\xa2\x07\x18\x23\x50\xc5\x6b\xe3\x78\x32\x89\xc2\x68\x14\x99\x48\x4e\xbc\xa6\xeb\x74\x7d\xff\xd6\xbd\x92\x89\x17\xdd\x9a\xec\xe4\x4f\x70\x4a\xd2\xc9\xef\x33\x84\xf1\xb7\x8e\xc3\x91\xbc\x76\x0d\xd9\x6e\xa3\x9d\xb5\x0e\x72\xd3\x0b\x6c\x57\xf1\x14\x09\x96\xeb\x0e\xa2\x1b\xa9\x1c\x04\x2c\xe7\xd1\x26\x39\x30\x64\x48\xae\x0c\x3c\x86\x89\xad\x9f\x26\x87\x96\x00\xff\x34\x2b\xae\x3b\x97\x8f\x7a\x10\x81\x81\x1e\x5e\x0d\x87\x77\x78\x05\xfd\xb9\x61\x1f\xe0\x65\x2d\x61\x7e\x4e\x34\x7d\xf4\xdc\xc9\x7e\x7f\x57\x1f\xbe\x33\x78\x65\xd8\x73\x8b\xdc\x4b\x03\x5b\xb0\xbd\x45\x29\x7c\x36\xec\x88\xfc\xb4\xb4\xfc\x95\x81\x77\xf6\x1f\x85\x6f\x86\xc5\xf0\xb6\xb6\x25\x77\x0b\x1c\x94\xac\x0d\x42\x91\xc6\x0b\x96\x6c\x03\x8c\x64\x3f\x41\xca\x4a\x7c\xb2\xd0\xbe\x90\xd4\x82\xca\x1e\xcd\xe8\xaa\xc0\xca\x03\x5c\xb2\xef\x20\x24\xeb\x43\x24\xab\x35\xd2\x9d\x22\x82\xbd\x90\xb0\xbd\x05\xca\x69\xa9\xec\xd1\x8d\x8b\x35\x1d\x64\xe3\xf3\x59\x16\x62\x50\x16\x67\xfd\x6f\x24\x29\xe9\xa9\x89\xd7\x7a\x6b\x50\xe7\x33\xe8\x3f\x84\xc2\x73\x43\xf4\xa3\xed\xad\x9c\x44\xe5\xba\xef\x02\x37\x9f\x77\x14\x1b\x92\x48\x22\x91\x04\xcd\x50\xd4\x0f\x97\x21\x63\xc0\x46\x99\x41\xde\xde\xfa\x4b\xfb\xd2\x76\x4c\xba\xd9\xdc\xde\x02\xb3\xd9\xc6\x10\x19\xaa\x6b\x17\xae\x3f\xa0\x81\xf6\x07\xc8\x0c\xf4\x25\x24\x60\x6b\x77\xf2\x6b\xee\x3f\x0d\x48\x49\xb4\xdf\xa7\x4d\x63\x37\xb1\x84\x1d\x90\x7f\xbd\x32\xd4\x8a\xcd\x7e\x3f\xd7\xe9\x96\x4b\xa6\x2b\x04\xb3\x29\x4c\x24\xfb\x05\x23\xb9\xc2\x2a\x93\xf2\x2b\x7a\xaf\x55\xf4\x3b\x94\xb0\xde\x86\xfb\x41\x20\x41\x06\xe6\xd1\xf6\xd6\xb4\x05\xfd\x20\xbb\x10\xcc\x59\xca\xc4\x1e\x90\x6f\xd8\x27\x7c\x88\xad\xa3\x98\x02\xcd\xf4\xa6\xed\x24\x33\x20\xdd\x44\x72\x90\xb6\xbb\x38\x4b\x37\x95\x03\xd6\xda\x53\xf9\xbd\xc3\xff\xda\xde\x02\xc9\x10\xae\x01\xb5\x69\x4a\x92\xd9\x80\x8c\xa4\x6d\x69\xd3\xd8\x16\x14\x9c\xd9\xa3\x20\xbb\xf9\x6a\x66\x14\x7a\x55\x6b\x60\x5d\xf9\x1b\x33\xd8\x90\x2c\x56\x70\x2d\x59\x5f\xc1\xa5\x7c\x80\xe1\x9e\xcf\xaf\x38\xf3\xb2\x45\xbf\xe0\xc7\xd5\x5e\xf0\xdf\xda\xca\x09\x5d\xf6\xa6\x9c\x65\xd7\x65\xcd\x9e\xbf\x95\x6c\x2c\xe1\x4e\xb2\xd5\xb1\x0c\xee\xf9\x4e\xc0\x21\xb4\xa4\x87\x9b\x40\x42\x38\x09\x0c\x84\xb7\x81\x02\xf1\x21\xc0\x41\xfe\x25\x99\x52\x70\xf8\xc0\x5e\xbe\x92\xec\x1b\xec\xd7\x6e\x68\xb5\xd7\xee\xea\xe0\x80\x5c\xd9\x15\x7f\x88\xd7\xed\x90\x9a\x9c\x4a\x26\x15\x0c\xab\x80\x7b\x1e\x5a\xa1\xe0\x60\x25\x50\xcf\x73\x50\x5b\x90\xbe\xa0\x73\x24\x6b\xee\x81\xb5\x90\x31\x98\x63\xa5\x40\xb2\xc7\xdb\x78\xb7\xe2\xf1\x0e\x63\xa6\xdb\x0e\x5a\x90\x30\xd9\x49\x0a\x7f\xa9\x66\xb3\x70\x10\x5e\x08\xc5\x8f\x1e\x99\xa9\x7d\x2b\xbf\x96\x76\x67\x3a\x9a\xb5\x5b\x7f\xe9\x26\x2f\xd9\x71\x12\xbc\x79\x6b\x82\x5b\x43\x5c\x4b\x9b\x3a\xb0\x22\xe7\x49\xdd\x46\x8a\xfa\x64\x28\x49\x42\xa7\xd3\x21\xf9\x25\xc1\xfb\xff\x78\x90\xd0\x52\x1b\xe9\x1d\x1a\x72\x2a\xc1\x0b\x6c\x1e\x62\x93\x72\x0d\x1c\xb9\x86\xf9\xc2\x82\x71\x9f\x43\xc4\x8e\x2c\xe5\xd8\x97\x20\x9a\x6d\x0b\x31\xa3\x51\x51\x21\xde\xa7\x15\x62\x16\x75\x0a\x45\xe5\x88\xdc\x49\xe4\xff\x0f\xa4\x73\x79\x8e\xd3\x33\x2c\xdf\x32\x45\xa1\x04\xee\x4c\x9e\x4b\xe1\x87\xac\x3c\xfb\x5c\x0f\xe5\x62\xa7\x92\xb4\x53\x8f\x3c\x70\x6a\xaa\x24\x63\x80\x38\x4b\x8a\x50\x62\x03\x72\xe2\xf0\xd9\x97\x8e\x22\x58\xa8\x88\x1d\x2f\x23\x95\x16\xb3\xd0\xb2\x80\x21\xf0\x51\x56\x08\x5a\x0e\x1b\xb3\x88\x8d\x4c\xb1\xe9\x7a\xe0\x3c\xc0\x64\x11\x06\x46\x16\xd8\x1c\x91\x1f\xb6\x99\x5b\xe3\xc6\x36\x69\xb6\xc1\x50\x8b\x13\x62\x94\xa0\x76\x77\xbe\xa8\x1b\x21\x8b\xce\xd7\x4a\x1a\x36\x94\xa5\xf0\xbe\x29\x32\x26\x45\xe6\xbf\x65\x31\x8c\x4d\x86\x8c\x3d\xe9\x78\xa1\xe3\xf9\x58\x46\x46\x36\xdb\x18\x8d\x0e\x51\xc1\xc0\x74\xb3\xf9\x82\x77\xe9\x5b\x85\x67\x92\x69\x05\xef\x65\x35\x3f\x7f\x26\x01\x9f\x64\x0b\x1e\x3d\xb2\xb2\x74\x77\x48\xbe\xda\x4d\x87\x4d\x3c\xb1\xc2\x75\x50\x94\x99\xcc\x15\x6a\xbb\x42\x4f\xb1\x90\x15\x36\x3e\x2d\xef\x50\x7b\x66\x28\x66\xa9\xe5\xb1\x64\x87\x0a\x5e\x48\x76\x2c\xed\x06\xfd\x52\xbb\x78\xe6\x67\x02\xaf\x6d\x87\xf9\x26\x28\xaf\x78\xee\xd2\xa3\x2c\x3d\x66\x11\x46\xfd\x8b\x5c\x7a\x3f\x4b\x0f\x59\xbf\x78\xcc\xd1\x8a\xfa\x09\xd8\x4f\x81\x9f\x31\x7e\xf6\x7d\x0e\x3b\xad\xd6\x9e\xe9\xa2\xd8\x66\xd1\x71\x51\x7f\x83\x23\xf2\x45\x3a\xad\x57\xb3\x0d\x21\xb5\xff\xcd\x6a\x41\xe9\x9a\x5c\xbd\x98\x3c\xff\x6e\xc6\x6f\x59\x6f\xbf\xcf\xdb\x6f\xb9\x55\xf5\x66\x6e\x55\x95\x1f\x14\x3a\x20\xbf\x25\xd4\xea\x61\x12\x03\xee\xf1\xb8\x5c\xcd\x46\xe1\xbb\x64\xa7\x0a\x5e\xcb\x3a\x8f\x94\x21\xf9\x2e\xab\x2c\x75\xc7\x92\x68\x74\xeb\x71\x60\x3e\xcc\xa1\x6f\x47\x4f\xd6\x80\xd0\x7f\x02\x7a\x98\x3e\xdf\x4c\x67\x76\x5b\xbb\x26\x7e\x4a\xf6\x5b\xc1\x3b\x59\x63\x9d\xc9\xb5\x83\x27\x8a\x20\xe4\x9f\x12\xfd\xf6\x90\x4c\x3d\x97\x4b\xf1\xc9\x72\x24\x5e\xcb\x8a\x20\x36\xad\x19\x10\xbb\x25\xdf\x48\x78\x27\xdd\x98\x01\x0e\xee\x07\x49\x12\x43\xe1\x58\x92\x33\x04\x9e\x7b\xc9\xc0\xcb\xb9\x36\xca\xbd\x69\x21\xff\x2e\xeb\x15\x64\xaf\x65\x7a\xc0\x75\x5e\x28\xff\x8c\x4f\xae\xd8\x7d\x18\xbc\x90\x20\x82\xe7\x12\x7a\xc1\x4b\xcb\x58\xfd\x2d\xa1\x1f\x48\x33\xc3\xf6\x5e\x49\xf8\x2c\xe1\x9b\x84\xb7\x12\x54\x02\x3a\x01\x93\x80\x4c\x20\x49\x80\x27\xec\x8d\x22\x9e\x85\xe2\x51\x10\x49\xed\xdb\x11\x09\xc9\x1b\xc6\x67\x1e\x12\xb6\x6c\xc0\xd7\xbe\x78\xef\xdc\x28\x4f\x60\xce\xbf\xc8\xf8\x9c\x28\xf2\x46\xa3\xaf\x50\x1e\x14\x4e\x93\x7b\x5e\x32\x3f\xf3\xb9\xb7\xc3\x39\x7c\xd0\x55\xc6\xfd\x78\x3c\x31\xdc\x48\x4b\x84\x6d\x09\xc5\x6f\xa2\x01\x37\xb1\xf6\x93\x89\xd4\xfb\x03\xa9\x4c\x61\x72\x3e\xd3\x51\x4f\x2a\xe3\xd1\xbd\xd6\x74\x5a\x09\xee\x92\x4f\x2e\xc5\x25\x57\x03\x07\xb0\x82\xfa\xae\x13\xed\x0b\xa3\x47\x6f\xe5\xdd\x74\xaa\xfd\x6b\x69\x78\xfa\x15\x43\xa3\xe2\xf7\xf6\x9e\x15\x2b\x13\x63\x62\x35\x9d\x2a\xdf\x70\x3d\x90\xc6\x7e\xeb\xc5\xb7\x6a\x14\xf3\x1e\xa5\xf7\x7a\xe9\xc6\x7f\x27\x33\xa8\x5f\x6a\xd9\x07\xc9\xec\xf0\x40\xc2\xde\xdb\xb3\xc7\xe7\x1d\x4e\x04\x49\xf0\x99\xb1\x5b\xc6\x58\xe2\x87\xb7\xf8\x23\x74\x3f\xdc\x03\x64\x13\x0c\x67\x9d\xe0\x97\x6e\xca\x67\x26\xb3\x20\x65\xa1\xcd\x8c\xba\x60\x99\x62\x3f\xa8\x54\x37\xa1\x8b\xac\x02\x6c\xd8\xd8\x72\x4f\x02\x74\x81\x15\x3b\x01\x3a\xce\x8a\x96\xfd\xdb\xb2\x20\xe2\x24\xd5\xf2\xf6\xf1\xcb\xf6\x0c\xc2\x84\x4d\x14\x4c\x12\x96\x28\x18\x25\xee\xb1\x3c\xb8\xc1\x2f\x9b\x5b\x33\xe8\x25\xec\x26\x81\x8d\x84\xf5\x12\xb8\x4e\xaa\xd8\x62\xfe\x36\x58\x6f\x43\x18\x05\x9e\x07\xe1\x10\xf9\xe3\xcb\xba\xf5\x77\xcf\x5f\x04\x1b\x09\xf0\xc3\xe0\xce\x00\x7f\x1d\x8c\x12\xe0\x47\xf6\x53\xc4\x96\x5b\xfd\x11\x5c\x27\x76\x87\xf1\x67\x81\x73\x84\x70\xb0\xf9\x77\x0b\x5b\x98\xe0\x0c\xf8\x96\x4d\x10\x87\x81\x04\xf1\xca\x82\x0a\xaf\x82\x33\x08\x47\x16\x5e\x78\x10\xac\xb7\x67\xd4\xe6\x2a\x08\xef\x02\x8c\x75\x74\x9f\x56\x3e\xb4\x3c\x30\x96\xfd\x6d\x3f\x0e\x10\xe7\xd7\x58\xed\x8d\xab\x16\x9e\x05\xad\x59\x16\xd9\x68\x46\x61\x90\x0d\xc6\x38\x61\xf7\x3c\x42\x8c\x87\xf8\x19\xe3\xe7\x4f\xfc\xbc\xc3\xcf\xdf\x78\x0a\xde\x56\x8f\x4f\x2f\x18\x24\x10\x7e\x75\x5a\x76\x0b\xeb\x34\xb8\x4d\x88\xe7\x51\xe0\x9f\xb2\x6f\x37\xc1\x38\x81\x49\x9e\xfe\x25\xfb\x16\x0a\x44\xf1\x24\xfb\x8d\xb8\xc2\xaf\x84\xdd\x87\x1f\x83\x51\x32\x83\xc3\xe4\x0f\xf8\xf3\x16\x6c\xa6\xac\xf4\x55\xc2\x8c\x82\xfd\x2a\x44\xc9\x90\x5c\x25\xc8\x57\xe1\x31\x7f\x98\x40\x1b\x14\x0d\x14\x6d\x7a\x8f\xf8\x38\x7a\x74\xb3\xe5\xcd\xe0\xd4\xe2\x3f\xb0\x83\xf7\x03\x11\xfb\x65\x3f\x3f\xda\x8f\x53\xfb\x71\x66\x3f\x5e\xe3\x60\x0c\x71\xf8\x76\x67\x70\x90\xac\x16\xa6\x8e\xb0\xe0\xd6\x0c\x4e\x6a\x0a\xee\xa4\x05\x7f\x64\x4b\xf6\x63\xb2\xda\xde\xf1\xb5\x26\x7f\x3b\xcd\x3f\x4b\x56\x9b\x7a\xde\xd7\xe4\x3f\x4e\xf3\x3f\x25\xf5\x86\x9b\xdd\xb2\xe1\xe6\x38\xdb\x6d\x2f\x1e\xc0\xf8\xcb\x03\x18\xff\x7e\x00\xa3\x37\x0f\x0c\xdd\xf7\x6c\x32\x5e\x27\x2b\xfc\x16\x89\x22\xee\xe0\xfc\x90\x54\x73\x8c\x55\xbe\xcd\x46\xdf\xdd\x7f\xd0\xb9\x27\x37\x53\x85\xd3\x43\xd9\xc1\x5b\x4b\x4b\x40\xc9\x7a\xdb\x39\xef\xc2\xcf\x84\xbd\x56\xf0\x2e\x61\xdf\x15\x3c\x4f\xd8\x3b\xdc\xf7\x2f\x13\xf6\x5d\xc3\xdf\xf5\x38\xde\xf3\x23\xbb\x8f\x2f\xed\x10\xff\x72\x63\xfc\xea\x81\xc9\xfc\xfc\xc0\xf2\xfb\xf6\xc0\xd4\xbc\x7d\xa0\xbe\xe2\xab\xa7\x46\xf3\xd5\x53\x63\xf8\xea\xa9\x97\x35\xf9\xed\x67\x69\x81\xe4\x01\x00\x9c\xd7\x3f\xbb\x16\x76\x91\xbd\x49\x1c\xdf\x15\x28\x4b\x3d\x6b\x8b\xa7\x9c\x91\xca\xb9\x22\xce\xe1\x0c\x4c\xc1\x0b\x45\x9c\xfd\xc9\x13\x4b\xf7\xfc\x4d\x60\x2c\x8d\x8b\x80\xb7\x82\x04\xf8\x6e\xa0\xd3\x39\xfd\x1d\x48\x4b\xec\x38\x84\x1f\x82\x18\xc2\xcf\x81\x40\xcd\x1d\xaf\x5f\x10\x61\xcf\x2e\x88\x77\x16\xc2\xdf\xf8\x78\x16\xf4\x6b\xc6\xe3\x09\x84\x38\x1e\x21\x67\xd7\x92\x28\x49\x61\x52\x0f\x77\x6d\x48\x42\x0e\x43\x32\x49\xa0\xb0\x51\x8f\x38\x13\x0a\x6e\xf8\x03\x86\x62\x2b\xc4\x8f\x38\x54\x69\x88\x9c\x7e\xc8\x4b\xd4\x58\xc7\x42\x4e\x26\xb2\xe7\xe5\xd7\x05\x2d\xc7\x88\xea\x21\x8f\x0b\x13\xdd\xc8\x72\x4e\x3b\xcd\x99\x24\xe3\xb1\x5e\xaa\xb7\x45\x17\xd5\x48\x37\x9c\x78\x9f\xd4\x95\x8a\x6f\xd5\x9a\xb9\x1b\xcb\x60\xcd\x6b\x2a\x3a\xb3\x54\x99\xc2\x06\x67\x07\x64\xc2\xc1\x8b\xd4\x65\x14\x46\x46\xf6\x9e\xdf\x79\xd0\xe7\xc4\x66\xba\x9c\x49\x34\x92\x4a\x54\x65\x38\xa6\xad\xc7\xe1\x52\x92\x98\x5b\xa1\x08\xae\x33\x78\x8a\x5f\x4b\x0f\x86\x89\xcd\xab\x18\xa2\x10\xe3\x64\x53\x0a\x97\xfc\x0f\x0d\xdf\x83\x15\x13\xbf\xa0\x61\xb7\xc5\xc7\x73\x70\x45\x76\x41\x28\x62\xaa\x53\x11\xc4\xd7\xa9\x90\xa2\xd4\xf5\xb7\xcd\xca\x6f\x90\xac\x0d\xc9\x25\xbe\x3c\xed\xde\xd7\xc8\x3c\xec\x38\x64\xfe\x1a\x82\xd8\x8c\xd4\xed\x06\xaf\xce\xf8\x1b\x15\x3a\x0d\x04\x63\xa6\x53\x0e\x89\x1f\xd2\xd9\x5c\xde\x01\x19\x14\x79\x90\xf8\xc2\x52\x46\xb8\xe5\x6c\xcc\xe1\xee\x4f\x47\xe8\x17\x5f\x65\x85\xe0\x1f\xed\xe0\x0c\xec\xa6\x32\x76\x9b\x1c\xba\x1d\x72\xc8\x53\xce\xe6\x8a\xd7\x4b\x27\x77\x1c\x0e\x39\x1c\x91\x5f\x1c\x94\x1f\x1e\x82\xf2\xf9\x47\x74\x3e\x11\x78\x44\xec\x73\x46\x5e\x49\x3c\xde\x5a\xb3\x2a\x79\x6e\x4c\x0e\x5d\x70\x41\x8c\xf1\xde\xc5\xde\xae\xb7\xd1\x3c\x1e\xe0\xb0\xac\xb7\x61\x48\xae\x38\x28\x78\xe5\xb4\x4a\xa7\x9c\xbd\xd4\x30\xe4\x0f\x28\xa2\xdd\x20\x1f\x90\x53\x8e\xd2\x71\x92\xc6\x2f\x1c\x13\x0e\x9b\xed\x5c\xc1\x82\xed\xdd\x91\x04\x63\xee\xed\xb5\xa0\x05\x76\x34\xac\x70\x95\x60\xf4\xa7\xc4\xef\xe1\xd2\x09\x2d\x63\xc8\x83\xc4\xe7\xb3\x02\xcc\x16\xa5\xa9\xa6\xba\xd9\x06\xc3\xf0\x6d\x75\xd6\x86\x84\x25\xce\xad\xdb\x65\xf2\x54\x87\x2d\x9b\xed\x4c\x7b\x7d\xc0\x59\x85\xc8\x5b\x31\x3a\x03\x32\x74\xae\x3c\x61\x69\x74\x71\x87\x1e\x71\x76\xc0\xe1\x64\x6e\x66\x4a\x77\xdd\x56\x2c\x65\xfe\x9f\x2c\xe5\xd0\x2d\xe5\xb9\xc5\x68\x0b\x0d\x49\x02\x4e\xa7\x6b\x8b\x20\x7a\xdc\x92\x3f\x2b\x91\xcf\x28\xfc\xe0\xd5\x9c\xc1\x09\x87\x11\xde\xcc\x81\x8f\x95\x25\xf0\x3d\x92\xb6\x3b\x53\xa1\x12\xc2\xdc\x8a\xb0\xc2\xa9\x33\xfd\xce\xe0\x2b\x67\xef\xe0\xec\x4f\x07\x36\x5b\x67\xda\x8d\xe6\x7b\xce\xce\x38\x7c\x9a\xc7\x29\x7b\xd8\x23\x0f\xa6\xf1\xe8\xfc\x9f\xc9\xaf\x30\xbe\x78\xe4\x1b\x39\xc1\x98\xde\xf3\x6a\x3a\xcd\x9a\xaa\x70\x43\x62\xce\x4c\xef\x34\x5f\xc7\x96\xda\xdf\xf2\x45\x1f\xc4\x67\x7b\x87\xb2\x04\xe7\x23\x27\xe9\x1b\x49\xb2\xb7\xc6\xcd\xda\x75\x3c\x31\x6b\xcf\xd6\x7a\xd1\x20\x32\x13\xc0\x17\xc8\x06\xb1\x71\xb6\x5a\x57\x91\xa6\x0d\x7f\xe2\xc4\x6b\xf9\x96\x7a\x17\x9e\x8f\x1b\xdd\x8f\x9c\xfc\xeb\x48\xb9\xc7\x03\xfb\xa3\x98\x9b\x60\xcd\xfb\x57\x53\x35\xff\xe5\xfd\x8b\x06\xef\x39\xf9\xca\x49\x5b\x6e\xff\x85\xe1\xa8\x66\xf0\x83\x93\x23\x4e\x5e\x18\x4b\xac\x5f\x70\x36\x96\xf0\x85\x3f\x60\x43\x58\x7b\xc1\x89\x6a\xee\xb6\xfe\xd2\x7f\xed\xb6\xfe\x6a\xcb\x6d\xfb\x9d\x98\x4d\x4e\xf1\x87\x05\x2e\x9b\xe8\xab\xf9\x7b\x8e\x46\x47\x85\x6b\x5b\xcc\x14\xf4\x0b\x05\xcd\xf2\x7a\x8d\xff\x73\xd2\x1b\x42\xc2\xfa\x56\xde\xfd\x5f\xa1\xbb\x99\xb3\xba\x58\xa6\xc0\x43\x12\xd9\xfe\xfb\x21\x05\x47\x86\xdf\xac\x70\xc6\xfb\xed\xd6\xba\x13\xa8\xbe\x73\xf6\x86\xc3\xeb\xd5\xc5\xdf\xe6\xc5\x3f\x70\xb6\xf8\x8e\x77\xea\x1e\x51\x3f\x4e\x49\x3a\x4e\x0f\x8e\xd1\xf2\x6e\x96\x78\x4c\xb9\xc7\x36\xe0\x27\x67\x1f\x38\xbc\x2b\xed\x85\x32\xbb\xb3\xbc\x86\x1d\x05\x47\x7d\x57\x8a\xc9\x91\x24\xf5\xeb\x30\x52\x46\x0e\xa4\x5e\x58\x89\xba\xf4\xc2\xdb\xdc\x2e\xc0\xb5\x6e\x68\xd3\x5b\xb9\x0b\xe6\x16\xef\x0c\x9e\xf3\x3f\xf4\xad\x7b\xc9\xd9\x73\x0d\x7f\xf3\x4a\x73\xdf\x0c\x5e\xf1\x25\xa7\x1c\x8e\x5e\x06\x02\x3d\x54\x22\xb6\x3e\x94\xa5\xab\xce\xcb\x73\x32\x20\x2f\x39\xf0\x45\xfa\x8d\xa4\x72\x6e\xb1\x96\x26\x65\x4c\x8c\x3d\xa0\xba\x0b\xa4\x4e\x50\x1a\xe0\x7c\x45\xe9\x19\x95\xcc\x45\x28\x0c\xdd\xb9\x2d\x6d\xe7\xec\x19\x65\x25\x1a\xce\x5e\x71\xf8\x56\x49\x67\x3f\x73\x32\x24\xcf\xb9\x7b\xbd\xe5\x29\x92\x5b\x3b\x6e\x6f\x2b\x0b\xdb\xf9\xc8\x66\xaf\xc7\xef\x02\x37\xf2\x4e\xbd\x2b\xd8\x6b\xd0\x82\xdd\x82\x11\x55\x63\x48\x86\x44\x09\x78\x0c\x8a\x4e\xa7\xeb\xf8\xbd\xdd\xb2\x47\x7b\xa3\xe1\x32\xf0\x07\x9d\x81\x14\x55\xde\x4f\x9b\x59\x1c\x3e\xa2\x1f\x3d\x9e\xb6\xe8\x26\xd1\x8f\xda\xad\xd6\xb4\x45\x9b\x36\x05\xbf\xcd\x20\x11\xcb\xa4\x35\x0b\xfa\xc1\x31\x34\x71\xe8\x62\x48\x38\xb3\x5d\x6e\x9b\x7e\xcb\xed\xd4\xb9\xa6\x96\x1b\xdf\x6e\xef\x6c\xef\xca\xdd\xbf\x88\xdc\x6c\x3f\x7b\xd2\xb2\x13\xf6\x74\xf7\xb1\xdc\xf9\x8b\x90\x64\x6f\x7b\x3a\x5d\x37\x82\x48\xda\xe5\x9b\xed\x80\xd3\x26\x41\xdf\xea\x4d\x29\x08\x16\x2e\xa2\xf7\xbe\xb7\xf4\x51\x37\x0d\x9d\x65\xaf\xd5\x25\xf9\x33\x2a\x99\x2d\xb7\xbd\xc7\xbb\x88\x4c\xa0\x33\xde\xbe\x64\xfa\x7d\xb6\xc7\xa7\xd3\xad\x67\x8c\x31\xde\x68\xa4\xad\x66\xa5\xb7\x76\x9f\x3c\x7d\x2c\x77\xe8\x42\xd0\x90\x39\x88\x3b\xad\x67\x4f\x76\xf3\x32\x79\xd8\x91\xed\x56\xa9\xcc\x93\x27\x4f\x76\xe5\xee\x62\x18\x85\x39\x30\xed\xd6\xf6\xee\xd3\xbc\xcc\x6e\x25\x98\xf6\x76\xeb\xf1\x6e\x81\xcf\x93\x6a\x40\x3b\xbb\xdb\x25\xa4\x9f\x56\x17\x7a\xba\xdd\xde\x7d\x9a\x17\x7a\x56\xd9\xdc\x56\xeb\xd9\xb3\x9d\xad\xbc\x50\xf1\xe0\xde\x1c\xa8\xad\xed\x9d\xa7\x4f\x4a\xa5\xda\xd5\xb0\x76\xb7\x76\x77\x8a\x61\x2a\xde\xf5\x9b\x87\xf5\xf4\xe9\x8e\x1b\xcc\x05\x41\xaa\x4c\xe0\xae\x63\x65\x2e\x91\xbc\xa1\xb1\x18\x49\x9c\x15\xa9\xc8\x6b\x5e\xfa\x78\xcf\x49\xad\x50\xb9\x9f\xbf\x97\x40\x61\x48\xbe\x5b\x62\x4c\x1e\x53\xf8\xc6\x89\xb7\xe9\xd1\x52\xe2\x56\x39\x11\x7f\x53\x0a\x5c\xd4\x13\xbf\xad\x32\xf1\x13\xa2\x42\x6c\xca\x3d\xf4\xee\x17\xcd\x8c\x96\x4e\x91\x16\xde\xbf\x49\x4f\x9a\xe2\x50\xb5\xbf\x08\x67\x09\xf5\x73\x73\x38\x4f\xbd\x38\x86\x84\x0b\xd0\xc0\xf1\x80\x61\x72\xd9\x39\xcc\x1e\xc9\xb3\x05\xfe\x0e\xdf\x93\x81\x48\xfc\x31\x37\x27\x04\x28\x2b\x88\xd8\x8a\x10\x0b\x16\x09\xe8\x8b\x7a\xb1\x5d\xfd\x45\x2c\xd3\xd2\x44\x79\x3d\xac\x20\x20\x69\xb9\x58\x90\x63\x72\xbe\x30\x75\xe5\x8f\xef\x38\x93\x5f\x2c\x4f\xed\xe6\xe2\xcc\x5b\x9e\x9f\xa0\x6a\xd2\x82\xd2\xa4\xc1\x5c\x3b\x0e\xe6\x58\xba\x72\xbe\x05\x78\xcc\xa9\x4d\x6b\xd1\x0b\x5a\x2a\xfd\x93\x57\x1b\xa7\x6c\xb5\xef\x0e\x8f\xc5\x35\xd7\x17\x0f\x54\x6f\xbb\xea\x4d\x57\xbd\xaa\xc8\x66\x5a\xc4\xae\xba\x8b\x07\x3a\x56\xe4\xbf\xe7\x64\x44\xbe\xd8\x13\xa7\x95\xfd\x4f\xad\x78\x68\x8b\x58\x1a\x4e\x61\x22\x56\xe8\xf3\xac\x84\x3a\x27\x9c\x8e\x44\xb5\x4f\xed\x44\xcc\x9d\xb4\xa1\xa1\x33\xb8\x11\xff\x91\x23\x6a\xee\x05\x5e\x7a\xee\xca\x79\x7a\x2a\x3c\x52\xb4\x73\x47\x42\x8f\xa2\x92\x37\x67\xd9\x17\x51\x2e\x14\xbf\x11\x2e\x04\x6b\x69\xf1\xcf\x28\xf4\x44\xdd\xfb\xf6\xc4\xf6\xb8\x0d\x22\x38\x83\x1e\xbe\xbb\xd7\xb2\x1d\x6f\xbb\xb7\xc9\x3a\xb9\xdd\x6c\xa3\x8b\x4f\xab\xde\x08\xbc\x83\x71\x46\xf1\x31\x6c\xe3\x9e\x4f\xd8\xa8\x03\x3e\x24\x3d\x01\xe5\xd0\x07\x39\x9c\x37\x12\x46\x02\x37\x78\x0a\x88\x63\xf8\x04\x51\x2d\xcb\x6d\x08\x08\x05\xca\x72\x97\x62\x59\x95\xe5\x4e\xd1\x6b\xb1\xc0\x09\xde\xcc\xf1\x12\x26\xd5\x38\x05\x97\xd2\x71\x80\xa8\x78\x1a\x08\xb6\xea\x51\x97\xfb\x8d\x60\xb3\xbd\xe8\x35\x09\xd2\xb9\x2c\x8d\x45\xbd\x5b\xcd\x26\x06\x93\xf6\x37\xa6\xd3\xc4\xe7\x45\x8a\xb4\x29\xd2\xe7\xd3\x69\xfa\xb3\xe7\x12\x7a\x05\x2d\x1b\x90\x81\x80\x02\x58\xea\x83\x23\xfd\x5e\x27\x64\xd2\x97\x9d\x72\xb1\x16\x8a\xc3\xd2\x17\x80\x3f\xdb\x96\xf2\x01\xf7\x05\x70\xbf\x07\xdc\x97\x34\x4b\xb7\xd0\x42\x48\xd2\x77\xed\xac\xc4\x11\xe2\x8d\x58\x01\x31\x4b\xfc\x1e\xf4\x59\xe2\x5e\xb7\x9e\xc3\x72\x01\x25\x01\x11\xa4\xcd\x3a\xec\x62\x0a\xfd\x34\x3c\xf4\x02\x5a\x36\x3f\x6d\x3a\xc3\x50\x5a\xce\xd1\xf6\x20\x47\x0a\x35\xb0\xd0\x47\x45\xcb\xad\x60\x87\x70\x27\xaa\x7d\x66\x16\xaf\x06\xa5\x8d\xd8\x02\x37\x09\xdc\x24\x34\xbf\x43\xc1\xf1\x69\x8d\x10\x83\xac\x0b\x10\x78\x79\x28\xc2\x70\x79\xe9\xde\x1b\x92\x5b\x81\x37\x92\x16\x77\xe0\x80\x8c\x45\xaa\x19\x3e\x20\x77\x6e\x06\x04\x85\x68\x31\x74\x32\xb6\x8d\x2e\x8f\x18\x23\x70\xf1\x70\x2e\x81\x11\x05\xa0\x08\xad\xa5\xf0\xab\xaa\x7f\x0e\xf5\xbc\xa8\x73\x00\xaa\x9c\x86\xf9\xb9\x9f\x1f\x59\x3b\xae\x33\x0a\x87\xe2\x3f\xbd\x21\x72\x40\x7e\x09\x7c\x36\xda\x3d\x6c\x6d\x29\x45\x82\x1b\xed\x4a\xd4\xe8\x94\xb7\x52\xa5\xf5\x7e\xdd\x5e\x95\x70\x28\xe0\x4a\x38\xae\xfd\xb4\x06\xcc\x33\x2b\x52\x58\x56\xa5\xae\x99\x1d\x18\x60\x81\x83\xea\x66\xf0\x5c\x39\x15\xe4\xce\x58\xa2\xbf\x21\xe1\xd6\x80\x72\x04\xfe\x48\xb0\xfb\x8d\x60\x67\x06\x27\x73\xe3\x3d\xff\x0a\x52\x0d\x11\x19\x92\x30\x81\x04\x96\xa4\xdb\x4b\x0c\x8f\x5f\x96\xfc\xb1\xa4\x43\x83\xc3\xa9\x20\xc2\x36\x5e\x7a\xbe\x4e\x3a\x0a\xf4\xda\xe0\xbb\xe0\x48\x76\xf0\xb1\x1a\x38\x12\xe8\xaf\x26\x56\x3d\x4d\x85\xaa\xfe\x03\x72\x22\x32\x7d\xff\x91\x40\xe7\xb3\xf4\x22\xdd\x47\xc1\x0a\xdd\x77\x32\xf1\x60\x83\xa7\xca\x70\xa9\x7a\x93\x7d\xe3\xc1\xa5\x48\x13\x92\xb1\x25\x7d\xbd\xb9\xb4\x89\xe1\xda\xcc\x17\xeb\x47\x6a\x20\xf5\x58\x47\xca\xa0\xba\xdc\xa5\x6a\x29\x64\x74\x23\xf5\x04\x55\xee\xd7\x3c\x53\xb9\x73\xa5\x62\x83\x46\xb4\x89\x07\xfb\x02\x95\xf1\x47\xe4\x87\x00\x6f\x20\x95\xd4\xdc\xc4\xfa\xd3\xc7\x63\x0f\x0e\x5c\xd6\x9d\x49\xeb\x8d\x78\x28\x47\x45\x95\x4b\x49\x22\xd4\xd7\xbb\xff\xe0\x6b\xd6\x2d\x3e\x92\xda\xb8\x46\x3f\x0a\xba\x80\x8c\x07\xd7\xbc\x16\xde\xdf\x09\x42\x3a\xab\x5c\x34\xaa\xeb\x19\x9d\x48\x2f\xf0\xfa\x7c\x34\x91\xde\x0c\xde\x57\x97\xb3\x1b\xcf\xf3\x30\x0c\x1b\xef\x2a\xe7\x4e\x56\xbf\x77\x2d\xc3\x58\x9e\x75\x13\xb8\x1b\x1e\x78\xcd\x7e\x46\xe1\x58\xac\xd0\xc4\x48\xf8\x84\x61\xbd\xce\xdc\xe6\x7b\x21\xea\x2d\x63\x1b\xa9\x6f\xa7\x7b\xba\x08\x43\x76\x55\xa2\x2f\x95\x88\x7b\xf2\xd3\xc7\xa3\x83\xf8\x7a\x1c\x2b\x7c\x5f\x86\xce\xe0\x77\x65\xe1\x17\x82\x0c\xc9\xeb\x04\xbe\x08\x38\x34\x44\x35\x3d\xe6\xa1\x5a\xe3\x8d\x58\xf1\x76\x52\xaa\x67\x5a\xc1\x44\xa1\xc3\xc3\x89\x65\xa4\xbe\x3a\x43\xc8\x6b\xf1\xf0\x15\x26\xef\x87\xe7\x1e\x37\x4e\xef\x32\x7d\x10\xd5\x7a\xdb\x42\x9d\xe0\x0c\x8e\x2e\xc0\x5a\xae\x23\x61\x7a\xee\xb2\xfe\xff\x01\x05\xc9\x74\xda\xda\x73\xea\xfd\x0a\x7c\xbe\xcc\x21\x3f\x03\x7c\x85\xff\x7f\x5b\xa7\x92\xde\x32\x42\x3b\xe5\x0c\x7e\x0a\x76\x4c\xce\x4f\x88\xc7\xfe\xa7\x07\x5b\x14\x4e\x88\xb7\xfe\x3f\x3d\xd8\xc6\x6f\xcc\x83\x96\x4b\x62\x1e\xb4\xe9\x05\x85\x77\x82\xbd\x84\xe7\x35\xf4\xf9\x9d\x3d\x68\x3c\x8f\xce\xe0\x65\x35\x0d\x2a\x5b\x35\x12\x66\x88\xce\x8c\x4a\x28\x83\x2d\x2b\x35\x55\xae\xd4\xcc\x95\x9e\x50\x62\x31\x3a\xf8\xa8\xcc\xc6\x9c\x15\x04\xab\x08\x9f\xdb\x13\x54\x31\xfc\xa5\xf1\x39\x62\x67\xbe\x88\xec\x8a\xf9\x5b\xb0\x3f\x7f\xf7\xf2\x88\xbc\x14\x4e\xc7\x9e\x06\xe3\x82\x57\xe2\x01\x23\xbc\x78\xc0\x08\x5f\x47\x1a\xba\xaf\x04\x1a\x91\x82\xcf\xee\xef\x0c\xde\x8a\x7a\x9b\xd5\xdf\x76\xb4\x2b\xe7\xe1\x27\x87\x6f\x02\x9c\xef\x22\x5e\x79\x89\x56\x23\xac\xa3\xd5\x08\x9b\x08\x0d\x1a\xed\x19\xc8\x88\x55\x07\xa4\xa8\xd0\x1a\xe2\xaa\x36\xe9\xa6\x28\xd4\x8b\x63\xa2\xab\x34\x83\x92\xd2\x00\xb3\xb6\x32\xf3\x59\x66\xc6\x6a\x2f\x2c\x67\xe5\x87\xcd\x36\x4a\x50\x7e\x78\xd8\x6c\x67\xeb\x3a\x98\xaf\x65\xb7\x60\x73\xb1\xaa\xce\xaa\x15\x0a\x46\x0a\x49\x54\xbd\x9a\x65\x04\x0a\x4c\x44\x67\xc0\x6b\x4a\x64\xb4\xc2\x8d\x13\x9d\x81\xa8\x2c\xf8\x8a\x13\x1e\x39\x9e\x25\x8a\xaa\x74\x01\x99\x28\xeb\x04\x4c\x15\x11\x2b\x54\x8a\x88\x3c\x17\xf8\xfe\xbc\x13\x3d\xb3\x6c\x8d\xa1\x84\x20\x89\x2a\xac\xce\xde\x3f\xff\x38\x52\xb1\x50\x20\xd7\x64\xb6\x66\x25\x49\xf6\x21\x48\x2e\x20\xf0\xfa\x38\xa5\xca\x8e\x05\x8a\x71\x2d\x3c\x99\x41\x3f\xaa\x17\x47\x73\xd6\x5a\x2f\xb9\xe5\xa3\xea\x1e\x09\x62\x0f\x09\xe2\x22\xff\xac\xfd\xb0\xe0\xa0\x9d\xee\x45\x56\xdc\x59\x2c\x9c\xf6\x4d\xc1\x29\xbb\xe2\xc9\x9c\x7c\x3a\xa3\x10\x46\x35\x9b\x68\x7d\x48\xfa\xce\x86\xe3\x6f\xcc\x28\x4c\xa2\xfa\xcd\x16\x46\x99\x51\x63\x14\xb1\xfa\x87\x30\xcb\x04\x2e\x2a\x99\x6d\x53\x6b\x6b\x54\x32\xda\x66\x16\x5a\xbb\x3a\xf9\x9c\x75\x76\x96\x17\xae\x37\xcd\x02\x67\x96\x14\x8a\xb2\x89\x36\x9a\x37\xd1\x66\x45\xf0\xa2\x51\xc4\x96\xb5\x28\xdf\x05\x05\xf2\x56\xb2\x7b\xfe\x2d\x88\x23\x10\xcf\x03\xf2\x4d\xb2\x7b\xf1\x3c\x78\x2d\x40\x9c\xa2\xc3\xe1\xfb\xe0\xb5\x98\x51\x5f\x3c\xb7\x09\xdf\xa4\x2f\x4e\x6d\xda\x37\xe9\x87\xef\x67\x50\xb3\xe7\xdf\xda\xdc\x62\xdf\x63\x67\x74\xd9\x5c\xbd\xb0\xf5\xdf\x4a\x9f\x7f\xcb\xbc\x8c\x59\x46\x04\x42\x32\x8a\x6c\x96\x78\x0e\x6e\xc7\xa7\xdb\xbd\x9d\xca\x14\x3d\xf7\xe0\x5d\xa9\x98\x2e\x0e\xdf\xe6\x7c\x29\xbc\x42\x95\x9a\x79\xcd\x02\x3d\x1a\x92\x49\x04\x12\x41\x9c\x2e\x51\xa5\x14\xb5\x9c\xb6\xc8\x54\x9f\x19\x0b\xa7\x68\x58\xf9\x5c\x7c\xbe\xa1\xfd\x90\xc2\x07\xdc\xcb\xf6\xbc\xb5\x3b\x9a\x7c\x96\xec\x5f\xde\xbf\x9c\x6e\x0a\xb9\xa4\x7d\x49\xda\x14\x0e\x13\xd2\xa6\x14\x7e\x70\x32\xb7\xe7\x5b\x19\x39\xf8\x2c\x1d\x3d\x78\x2b\xe0\xb3\x84\x28\x4a\xd9\xdb\x5e\xb4\xe2\x61\x6d\xd8\x88\x56\xda\xeb\x7a\xf9\xd2\xbe\x8e\x56\xaa\x2c\xac\x04\x16\x59\x99\x33\x25\x57\x1b\x76\xdc\xd2\xb4\x21\xf9\x50\xc9\xc2\x7c\xb6\x03\x95\xb8\x50\x1d\xf8\x06\x37\xa2\xff\xa1\x4a\x67\xf7\x4a\x10\xbc\xc6\x88\xce\xf0\x17\x18\x41\x06\x2e\xa3\x55\xb2\x4c\x86\xc8\x43\x4d\x4b\x0b\x73\x48\xde\x70\x44\xf4\x0d\xc7\x8b\x37\x6f\xf0\x70\xa2\x0f\x22\x84\x95\xcf\xec\x1c\x20\x01\xa4\x30\xa8\x1b\xa5\xec\x4e\xd3\xc3\xbd\xeb\x3c\x3c\xa0\x7f\xda\xb7\x74\x58\x81\x5f\x60\x57\x78\x3a\x70\xe3\x39\x24\x97\x2d\xde\x19\xf8\x71\xa5\xeb\x16\x5f\xd4\x61\x20\xb7\x71\x4c\xce\xd5\x85\x15\xc7\xae\xa3\xbc\xd3\x8b\x4a\x8c\xf9\x82\x83\x72\xc1\x05\x7d\x06\xce\x00\x76\xd6\xb8\x3f\x49\xf1\xab\x80\x71\x40\x2e\xa3\x0c\x02\xc5\x57\x3e\x67\x33\x90\xb5\x53\x76\x36\x03\x9d\x4e\xd3\x6d\xc4\x0e\x78\xd5\xc9\xb6\x96\x8a\x02\x69\xa4\x49\xfc\xa6\xd3\x63\x13\xee\x52\x42\x99\xaa\xae\x71\x03\x12\x9d\xb0\x7b\x71\x1d\xf0\x88\x10\xe5\xbe\x7a\x33\x0f\xc4\x8b\xe0\x26\x02\xf1\x39\xf0\xc0\x03\xf1\x23\xb8\x8d\x2c\x69\xf4\xee\x3d\x10\xdb\x41\xcb\x12\xcd\x6b\x6a\x0b\xa9\xc4\x17\x2f\x6c\x39\xcb\x04\x24\xbe\xf8\x4c\x6d\x69\xfb\xed\x87\xad\xe0\x52\xc3\xf7\xd4\x56\xab\x77\xa3\x5b\x75\xcd\x72\x61\x64\xb7\x66\x33\x6c\x68\x1b\x57\xfd\x46\x04\xaf\x38\xd1\xae\x09\xb7\xb8\xb0\xe9\x01\x19\x67\x39\x16\x51\x97\xa8\x11\xd7\x34\xf5\xb3\x4b\xdd\xc6\x81\xdf\xe7\x94\xc2\xaf\xa8\x8e\x73\x4d\xe5\x47\x64\x5a\x0f\x71\x0c\x13\xd8\x10\xe4\x2e\xb2\x95\x28\x5c\x45\xff\x2b\xd7\x79\xac\xf8\xd3\x4d\xd7\xb9\xa6\x78\x93\x3a\xbd\xd2\xb3\x1f\x2d\xfa\xb8\xe0\x6b\xb8\x05\x57\xa0\x4a\x96\x78\x2b\x64\x9f\xd6\x60\x1e\xce\x60\x18\xad\x12\x8c\x55\xa0\x2d\xa3\x08\x07\x51\x65\x64\x8b\xf0\x6b\x11\x01\x4e\x1c\x36\xc9\x90\x0c\x23\xf0\x3c\x18\x92\x17\x02\x62\x09\xfb\x11\x19\x92\xab\xc8\xd1\xf8\xd3\x08\xb4\x24\xca\x3f\xa1\xd4\x9d\x03\xce\xac\xd6\xd4\xf6\xcf\x0c\x8e\x6a\x9a\xf8\x85\x17\x3f\xcf\x40\x32\xe5\x9f\xa2\x29\xf8\x23\x9a\x82\x5f\xa3\x01\xff\x07\x44\xcb\x21\x26\x0e\xa3\x1c\x13\xee\x2e\x49\x16\x71\x26\xd6\xce\x3a\x15\x47\xd5\x1b\xe9\x70\x3c\x48\x71\xbd\x35\xf0\x46\x10\xaf\x1f\x8d\x8c\xd4\x5e\xba\xf5\x08\x85\x98\x0d\xc9\xb1\xa8\x96\x3b\x7e\xe7\xfa\x3e\x3a\x83\xaf\x24\x02\x27\x59\x66\xfe\x95\x1e\xdc\x1a\x72\x26\x1c\x66\xeb\x78\xc5\x90\xa2\x74\x99\xbb\x66\x2e\x96\x90\x59\x89\xd4\x49\x74\x2e\xbb\xe5\x68\x82\xcd\x2e\x14\x38\xef\xf1\x98\xb5\x69\x03\x1d\x27\x63\x0f\x50\x79\x96\x13\xdc\xd6\x1e\x06\x87\xe8\x7a\xdd\x2c\x5e\x42\xc3\x83\x98\x06\x9e\x37\x83\x93\x28\x75\x14\xfc\x11\xb1\x50\xc1\xc7\x68\xd5\x53\xf6\x25\x03\xe4\xd7\xe8\x01\x07\xfc\x07\xa4\xab\xf7\x51\x7a\x25\xe0\x53\x94\x3a\xd0\x1f\x47\xb5\x17\xb7\x5f\x54\xae\xe3\x34\x90\xc8\x0c\xbe\xac\x5c\xcb\x37\x06\xf5\x3b\xc1\x65\x59\xd3\xf3\x7b\x69\x2b\x6d\xa6\xe0\x1a\x8d\xf4\x5b\xaf\xf4\x5d\x5a\x49\x3d\xd3\x23\xdb\x9f\x68\x67\x70\x5f\x78\xb1\x68\x7b\xb8\x66\x65\x47\xa0\xd2\x3c\x42\xa5\xb9\x8b\xb8\x15\xa2\xd2\x7c\x5e\xdf\xec\x78\x45\x91\xdb\x00\xfc\x10\xac\x94\xa0\xf1\x7d\xbd\x4c\xad\xdf\x42\xb5\x3e\x3e\xfd\x38\xcb\xe2\x01\x2a\x8c\x24\xa6\xf0\x39\x36\x8e\x0d\x71\xb4\x3c\x10\xc9\x38\xea\xae\x7b\x14\xfa\x4c\xfa\x12\x42\xc6\x1f\x32\x71\x2c\x60\x91\x3a\xaa\x42\x62\x25\x15\x8b\x45\x3c\x67\x5f\xe8\x23\x22\xc5\x7d\xf5\x37\xff\x5b\xe3\xd8\xcb\xc6\xb1\xb7\x3c\x8e\x76\x18\xf0\x11\x5e\xb4\xd3\x84\x30\x61\x16\xe9\x11\x93\x7e\x0f\x6e\x96\x2c\x37\xed\xb2\xb3\xc8\xe2\x88\x1a\xf7\xea\x5b\x3e\xa2\xe9\x5b\xf7\xe9\x88\x96\x2b\x0a\x6c\x3c\x62\xc2\xef\xe1\xd3\x9f\x12\xf0\xed\x18\xc0\x5b\xa6\x30\x61\x7d\x44\xa1\x8f\x28\xf4\x97\x46\x56\xf8\x21\x88\x62\x64\x23\x3b\x35\xbe\x80\xc8\x82\x2c\xd9\x69\xac\xd4\x14\x2f\xe1\x52\x1e\xd5\xef\xab\xa4\xad\x6c\xf8\xb8\x1d\x3a\x6e\x87\x6d\x5e\x02\x75\xcf\x73\x6d\x34\x1a\xee\x0b\x2f\xa7\xf6\xd2\xf1\xcf\x7e\x15\xac\xd1\x1b\x2b\x16\xcf\x30\xb4\x60\x61\xdd\xaf\x4c\xd4\xb3\x72\xaf\xcd\x9c\x8d\x2c\x5b\x62\x16\x57\xbb\x3c\x5d\xb0\xa1\x3f\x5a\x23\x25\x51\x22\x0f\x22\xa4\xd0\x11\xdb\x2d\x77\xbb\x20\x05\xae\x87\xdc\x2d\x90\x57\x0d\x86\x13\x42\x7f\x67\x4e\xdf\x9b\xd9\x3d\xf9\xfc\x16\x71\x69\xd6\xc6\x76\x72\x78\x3e\x51\xaf\x23\x12\xd9\xbd\x13\xe7\x73\x71\x93\xcc\x75\xd6\xcd\xc3\xeb\x08\xdf\xa0\xa0\x7f\x90\x75\x93\xcc\xe0\x43\x54\x75\x55\x7c\x51\x51\x70\x93\x54\xf8\x41\xda\xc5\xcb\x71\x27\x08\x54\x1a\x44\x7d\x72\x87\xb1\x58\xf7\x5a\xc5\x38\xf2\x6c\xae\x4b\xdd\xe7\x7e\x2f\x37\x7b\x45\x76\x68\xa2\x2c\x2f\xb6\x43\xa3\x8b\xa1\x89\xb3\xa1\xe9\xb3\x78\x61\x68\x62\x9f\x43\xec\x87\x10\xfb\xc2\x72\x9e\x56\x60\x8a\x91\xb4\xd4\x0d\x8f\x5b\xa4\x69\x51\xbe\x34\x44\xf5\xd9\x43\xf2\xd3\xa6\x85\xe4\x7b\x04\xf3\xab\x1d\xef\x07\x57\x0f\x60\xe6\x53\x7a\xff\x47\xe3\x36\xc6\x71\xcb\xc6\xa7\xea\x26\x7b\x41\x96\x36\x52\x73\xb2\x5b\x97\x79\x90\x51\x65\x13\x66\x33\x92\xbf\xc6\x92\xad\xad\x2e\x0e\x97\xc9\xd7\x11\xb7\xeb\x40\x50\x1a\x94\xc7\x67\x2c\xf2\x6e\xa5\x43\x20\x68\x79\x20\x29\xbc\x8b\x6a\xad\xfe\x1f\x9c\xb4\x9a\xcf\xa9\xb1\x38\x9a\xc2\x94\x69\x16\x88\x61\x16\xd6\xd1\x1e\x3d\xc6\x99\x32\x9f\x47\xb5\x06\x17\x4d\x52\x95\x90\xa1\x73\x86\x97\x21\x79\xe7\x52\x03\x67\xd5\x2c\x4c\x30\x2f\x6b\x4f\xf7\x30\xf0\x8c\xfc\x65\xbc\xf4\x98\xff\x3b\x62\x63\x09\xaf\x1e\x10\xb1\xff\x8e\xc8\x7d\xf8\x34\x90\x20\xc6\x01\xe1\x2c\x81\x97\xf3\xda\xb9\xcc\x96\xf8\x23\x72\xf6\x86\xa7\x39\x9a\xe9\x22\xb0\x87\xfc\x6b\x77\xce\xe3\x41\x8f\x0e\x09\x94\x82\xb8\x0d\x34\x88\x37\x81\x02\xd1\x0e\xee\x0c\x88\xdd\xc0\x80\x78\x86\xb7\x41\x9d\x27\xc0\x8c\xc2\xe7\x5a\xf6\x61\x40\x5e\x45\xe0\xbd\x3a\x3c\xf3\x2c\x0b\x0e\x27\x91\xd3\x18\x7c\x4b\x59\xfd\x1f\x96\xdf\x9c\x24\x90\xc5\x17\x1f\x26\xd4\x31\xfe\x6f\xa3\x15\xee\x4b\x44\xa7\x57\xf0\x54\xcc\x86\x0a\x74\xbc\xf2\x22\xb7\x8a\x61\x48\xde\x46\xee\xe3\x58\x82\xa2\x70\x83\x26\xda\xef\x72\x29\xe3\xd2\x50\x17\xa5\x80\x82\x89\xeb\xb5\x7a\x3a\x46\x55\xc0\x5b\x0d\x1a\xee\x10\x15\x52\xcf\x5d\x75\xbf\x25\x64\x65\x20\x9c\x4c\x22\xf3\xd2\xd7\x69\xd6\xe4\x2f\x21\x65\x4f\xf6\xbc\x79\x6f\x48\xef\xbd\x34\xb7\xb1\xbe\x5a\x73\x83\x95\xb9\x3d\x56\x30\xe5\xc3\x08\xf6\xed\x14\x86\x1f\x7c\xd1\xa7\x4d\x6f\xcd\x6b\xba\x1f\x47\xf0\x2d\x72\xef\xf3\x2c\x78\x44\x7a\x9f\x94\xcc\x9c\x8e\xb3\x98\xd7\x6b\x7d\x1d\x5f\xaf\xf1\x71\x14\xb8\x70\xe3\x0b\xf2\xa2\xf7\x8e\x8f\xfa\xb1\xbe\x96\xbd\xb5\x44\x8f\xd2\x32\x56\x84\xc4\x25\x94\x70\x27\x4b\x51\x90\x71\xed\xa6\xb4\x8c\xf4\x23\x0f\x65\xf6\xc2\xc4\xea\x38\xf0\x89\xd7\x3c\xb2\x64\xf6\xa2\xd8\x50\x26\x26\x43\xf2\xd9\x8a\xf5\x7d\x4e\xbe\x0a\x37\x4d\xc9\x7f\x06\x7d\x35\xd0\x8f\x29\x50\x1e\xbb\xe5\x59\x31\xa9\x59\x79\xd5\xf4\x1e\x2d\x19\xa3\xdd\x9d\x4d\xb2\x8a\x6d\xb7\x5b\x2a\x66\x2b\x5d\x1f\x2c\xdf\x85\x61\x07\xe2\x5a\xd7\x09\x11\xc3\x86\x73\x8a\x88\xe3\xff\x15\x09\x19\xc3\xcc\x63\xc0\x0b\xec\xe7\x0b\x41\x12\xf4\x69\x76\x3f\x87\x11\x71\x6a\x14\x0a\xb7\x86\xd2\xb2\x13\x06\x85\x7e\x5c\x1b\x06\x2c\xea\x93\x75\x9d\x47\xe0\x49\xe3\x12\xe2\x3d\x1a\x94\x24\x1d\x71\xc9\x2c\x0a\xa9\x83\xa4\x0b\x00\x16\xd7\xc7\xd8\xe8\xc7\xd5\x17\xa7\x50\xf7\xe8\x50\x9a\xc4\x6c\xac\x60\x14\xb3\xe7\x8a\x78\x63\xa9\x27\xd1\xc4\xbc\xb2\x8b\xe8\xf0\xd7\x98\xab\xde\xfe\x68\xe4\xc1\x24\xa6\x70\xb3\x62\x4b\xbf\xcb\xb5\x99\x1b\xb5\xa5\x7e\x10\x0d\xf7\xc2\x04\x0b\xbc\xd8\x7c\x38\xc6\xb5\x63\x72\xee\x56\x1b\xde\xf4\xbb\xa0\x55\x52\x73\x26\xd9\x1f\x4a\x98\x48\x34\xdb\xb8\x80\xad\xe0\xe1\xad\x1e\xa2\xfc\x1f\xce\x04\x77\x1d\x3f\x60\x7d\x57\x29\xa5\x86\xcb\xd5\x68\x87\xc3\x00\xe9\xc2\x19\x0c\xc9\x75\x0c\x87\x11\x28\xff\x75\x6a\xe7\x1b\xd4\xec\x21\xc7\x0d\xfc\x42\x76\x80\x0f\x90\x1f\x38\x45\x7e\xe0\x23\x46\x51\x7f\x8d\x42\xc1\x0f\xe8\xff\xa9\x68\xbf\x5a\xac\xd7\xfe\xd9\x83\x82\x3d\x5f\x2d\xd8\x8b\x2c\x3b\x55\x3f\x58\xb1\x3e\xaa\x10\xf5\xe5\x9c\xa8\x1f\xe3\x0f\x91\x4c\x4c\x7c\x8d\xcb\x26\x52\x03\x0f\x88\x61\x09\x98\xee\xad\x21\xce\x45\x83\x06\x96\xd2\x5f\x2c\xe8\x04\xfa\xb4\xfb\x95\x28\x98\xd3\x0b\xf4\xa9\xbb\x24\x3c\x8e\xad\x5c\xfe\x78\x06\xb7\x31\x7b\xa7\x89\xd7\x8f\x45\x32\xf1\x28\xdc\x2d\x0f\x77\xbd\x1f\xe6\x3e\x71\xd3\x17\x05\xca\xe7\x5d\xcf\x0b\xb4\x1f\x46\x80\xb3\x19\xc6\x29\x9b\xaf\xfd\x70\x48\xbb\xf6\x33\xf8\x6a\xa9\xfb\xd0\x8e\xb4\x71\xea\xcc\xf5\x16\xe0\x79\x35\x32\x64\x1c\x53\xb8\x8d\xb3\xc1\xd9\x0c\xb9\xde\xc4\x00\xfa\x4e\x4f\xb3\xec\xef\x59\x89\xc1\x41\x44\x0c\x2d\x21\x71\x15\x81\x16\xc4\x1e\x9b\x16\x89\xff\xbc\xc1\xed\xca\x8e\x5a\x38\x6d\x78\x9e\x2c\xde\x07\x48\x0b\xf1\xb7\xf3\x85\x16\x14\x99\xfb\x44\xa7\x39\xe8\xe3\x86\xd3\xf0\x74\x06\x87\x71\xb5\x7a\x24\x9c\xc1\x55\x5c\xc7\xda\x41\xc2\xb0\xc9\x1f\x01\x91\xcc\xf8\xc2\xc0\x61\x4c\x24\xbe\x95\xe5\x79\x34\x18\x13\x09\x8b\x1b\x9e\xa6\x5a\x4d\xb7\x20\xc0\x43\x75\x54\xe1\xb8\x7a\x42\x0c\xbc\x4b\x9c\x1a\xfd\x65\x62\x99\xcc\x43\x18\x92\x41\xec\x94\xf2\xf9\xe0\xfd\x4a\x07\x0f\x17\xe9\x66\x78\xb7\xd9\x8f\xe4\xa8\x97\x7a\x1d\xcf\x28\xec\xc7\xab\xed\xa8\x18\x0d\x10\x5d\xc6\x42\x8c\x31\xb5\xd9\x06\x8d\xa4\x78\xd9\x05\x5d\x17\x5f\x66\x14\x4e\xe3\x87\x1c\xe3\xe7\x40\x67\x01\xda\xd1\xe3\x3d\x6b\x04\x4c\x1a\x53\x16\x0c\xad\x68\xd0\x14\x5f\x66\x14\x86\xb5\x94\xeb\xb7\x21\x07\xe4\x34\x4e\x03\x35\x63\xec\xeb\xb8\xda\x21\xb3\xb5\x97\xc7\x8a\x3f\x71\x8f\xdb\x16\x18\xeb\x32\xee\xeb\xb2\x1c\x24\xce\x74\xf2\xa4\x34\x86\x9c\x25\xe6\xd2\xe7\x34\x15\xd9\x3b\xee\xaf\x9e\xa5\x3b\xd4\x66\x65\x5c\x5b\x56\xa4\x14\xc8\x36\xc1\x68\x5c\xc5\x41\x90\xf8\xe8\x87\xe2\xf3\x8b\x7c\xb9\xbb\x10\x5e\x59\x8b\x99\x2f\x6d\xe8\x14\x51\xa5\xaa\xdc\x77\xfe\x28\xc2\x55\x4f\x75\x08\x3a\x5f\xeb\x65\x38\x18\x1f\x67\x1e\x68\x84\x40\xad\xb4\x1e\x82\x15\x4c\xc3\x5c\x03\x13\xfa\x1c\x46\x2c\x2c\xc7\xfc\x4a\x0c\x4a\xf1\xf8\x25\xce\xbe\xf4\xb3\x2f\x13\x68\xcb\xed\x3d\xd5\x1d\x92\x61\x0c\x7a\xf3\x31\x8c\xac\x38\x73\x10\x83\x6a\xb6\xd3\xdf\x18\xf7\x2b\x1b\xaa\xa5\x59\x3e\x26\xe7\x32\xed\x45\x6e\x6f\xa1\x70\xb4\x82\x0d\x3a\x88\x8b\xc0\x86\x27\xb5\x7b\xb3\x1c\xfd\x6d\x51\x5b\x6e\xfc\x10\x37\xd3\x51\x0c\xb2\x89\x01\xf3\x62\x90\x9b\xb8\x40\xdd\xfe\xf9\x11\xd7\xbb\x93\x59\x49\x58\xe1\xf2\x46\xdf\xc6\x98\xfd\x0d\x5f\x6b\x98\xb1\x8f\x71\x11\xc5\xfa\xac\x8e\x17\xcd\x25\xeb\x9c\x06\x18\xa7\xde\xaf\xd4\xdb\xa7\x85\xd6\xc7\xc4\x39\x6e\x35\x1a\x96\xca\x38\x6e\x07\xe3\x8e\xc7\x2b\xa3\x95\x3f\xe4\x24\x97\xfe\xf9\x14\x57\xe9\x04\xc6\x73\xa1\xd6\xdb\x59\xa4\x1f\xe6\x42\x57\x26\x2e\xb8\xc5\x8f\x98\xbc\x47\x09\xea\x7d\xec\x22\xa3\xb7\x41\x52\xf8\x1a\x3b\xaf\x13\xce\xdc\x8d\x48\xc1\x08\x46\x5a\xe5\x20\xe9\xa3\xad\x69\x8b\x6e\xb6\xc1\x8a\x7d\xc2\x2e\xab\x93\xd8\x85\x53\xac\x83\xc7\x11\x9e\x33\xb3\xc6\xec\xc4\x90\x88\xda\x65\xfc\x88\x43\xc8\xe2\x47\x12\x26\x2c\x8b\x41\x86\x73\x7e\x16\x93\x24\x65\x5e\xff\x36\xc0\x25\xf1\x77\x6c\xcd\x88\x02\xb2\xcb\x63\x83\xf1\xe1\x72\x12\x1c\x77\xdb\x8f\xb6\xff\x22\xfd\x66\xd8\x24\xf1\xe6\x84\x3e\x8a\x69\xd0\x9a\x51\x38\x8e\x57\xc4\xa2\xcf\xa8\x8b\x2a\xe2\xe8\x72\x3f\x9c\x4e\x17\x29\x4a\x39\x36\x5f\xd9\xf1\x2c\xdf\x8f\xd9\x0d\xfa\xc8\xb2\xc3\xf7\x8a\x09\xd0\xcc\x1e\xe5\x5f\x89\xb1\x67\x09\xb7\x07\x37\xbe\x97\x8f\x74\xed\xc4\x94\xc2\x33\x9a\x94\x6b\xb6\xc5\x0d\x3a\xa9\xbc\xa8\x5c\x97\x2f\x88\xa2\xfe\x30\x8e\xf0\x85\xde\x19\x7c\xa9\x5b\x31\x5e\x66\xc9\xb4\x7f\xb5\x65\x2f\xc6\x59\xfc\xe1\x17\x31\x39\x20\xc7\xb1\x9b\x06\x37\xb9\x29\x0d\xfe\x5d\x43\x83\xe7\x81\xd1\xdc\xec\x58\xb1\xac\xb2\xee\x34\xfd\xad\x9d\xbf\x0e\x25\x19\x92\x2f\xb1\xbb\xd1\xfe\x17\x69\x6f\xba\x48\x7e\x7f\x88\x73\x2b\x43\xb9\x1d\x1c\x90\xdf\xee\xac\x18\x92\x4f\x71\x1e\xbd\xed\x7b\xcc\x7e\xc3\xeb\xb8\xd2\x21\x20\xa5\xea\x26\xe7\xbb\xf2\x5b\x7b\x27\x44\x96\x4f\x69\x59\x3a\xa5\x1d\x0b\x32\xc0\x98\xca\xf4\x4f\x4f\xec\xce\x3c\x5b\x77\x40\xae\x1c\xaa\x3f\x88\xc4\xf0\x5b\xc6\x71\x77\xd2\xe7\xdf\x41\x98\xe0\x2b\x91\x96\xd7\xb0\x47\x08\x33\x7e\x68\x45\xb1\xf0\x2a\x38\x9b\xcd\xf3\x69\x49\x29\xd6\x7b\x35\xc8\x24\x87\x98\xb1\x6a\x09\xb5\x9d\x31\x0b\xf0\xb6\x8a\x7e\x63\xf5\x70\xe4\xba\x57\xf0\x60\x8f\x17\x4a\xf0\x2d\x5b\xc2\x45\x15\x2b\x97\xdb\x59\x84\x74\xb0\x08\x69\x7b\x11\xd2\xdb\xc5\x12\xbb\xe5\x12\x9c\x65\x1d\xb2\xdd\xb5\xe5\xee\xc3\xab\x60\x28\x09\xf7\xf9\x77\xda\x3d\x0b\x5c\xa4\xd8\x35\x0f\x5c\x02\xf7\x6d\xb6\x25\xfc\xed\x16\xfc\xb6\x84\xf6\x7b\x0c\x6f\x62\x57\x1c\x8a\x73\xa2\x52\x5e\x09\xf1\xa1\x22\x3b\x3e\x33\xf8\x9b\x53\x88\x0d\xe1\xbe\x78\xe5\x9c\x08\xca\x7d\x5d\x60\x39\xed\x72\xb1\xfc\x66\xa6\x11\xfb\x10\xa7\xee\x6e\x3f\xeb\x96\x31\x46\x7a\x01\xf1\xd1\x19\x03\xdf\xc5\xab\x42\x94\x88\xdf\x81\x06\xf1\xda\x96\x7f\x17\x18\x10\x1b\x2e\x50\xfa\xf3\x98\x29\x03\x2f\xe3\x1a\x2f\xc3\x18\xee\x85\xc0\x48\x70\xc7\x18\x10\xcd\x1e\x51\x7f\xc7\xec\x91\xff\xdf\x1f\xc1\xab\x98\x69\x43\xda\x8f\x5a\x14\x3e\xd7\xd4\xff\x19\x5b\xb1\xed\x1a\x08\x1e\x4a\xd7\xc8\xd2\x0d\x23\xf8\x3b\x86\x97\x31\xf1\xce\x37\xcf\xff\xf9\xe7\xe2\x7e\x46\xe8\x5f\xcd\xae\x0f\xff\xfc\xf3\xcf\x3f\xff\x7d\x63\xfa\xdf\xfe\xf9\x67\x72\xe1\x51\x4b\x76\x5f\xc5\xe8\x92\x51\x3d\xd0\xca\x17\xaf\x67\x70\x68\x88\xf7\xcf\x3f\x1e\x75\x3a\xb7\xec\x15\x83\x19\x7c\xfb\xc3\xcd\xda\x2a\x46\x7f\x1b\xef\xe3\x70\x7f\xa3\xeb\x16\xdd\xef\x00\x0f\x87\xcf\x31\x3e\xe5\x66\x05\xe4\x40\x56\xc8\x13\xd9\x0a\xc4\xf0\x77\xb8\x6c\x12\x03\x76\x66\x3c\x54\x1a\x88\x8f\x68\xe1\xcd\x16\x93\xf4\xc3\xdf\x76\x19\xe4\x11\xf1\xec\x99\x91\xed\xfe\x0f\xe9\xee\xcf\x04\xcd\x7c\xf7\xff\xf1\xbe\x28\xf6\x34\xef\x2c\xe1\x97\x3c\x8c\x5e\xb6\xd6\xeb\x07\x3d\xbc\x9e\xd9\x9d\x60\xc5\x0c\xd7\x17\x17\x01\xb4\x72\xdb\x59\x14\xd3\xa0\x7f\xb5\x34\x20\x7c\xbd\xbc\xb7\x1d\x47\xbb\xdc\x87\x34\x9a\x60\x0a\xb2\x9a\xa8\x86\xbf\x02\xa4\xea\x3c\x95\xa0\x50\x05\x4d\x6b\x37\xdb\x8c\xc2\xdb\xb8\xc6\x3f\xa3\xeb\xdd\x67\x22\x39\xe0\x7b\x38\x6f\x24\x1c\x44\x96\x83\x6a\x7a\x33\x0f\xc7\x4d\xf5\x57\x6a\x4c\x5e\x5b\x0c\xde\xc6\xb9\x37\xb4\xee\xaf\xf2\xdf\x42\xbd\x08\x7f\x86\x8a\x11\x7e\x84\x9a\x11\xfe\x03\xf0\x09\x86\x3b\x08\xed\xaf\xd7\x30\x61\x49\xd3\xfb\x6f\x8f\x32\x45\xe7\x88\x0d\x62\x32\xa1\x9d\x5a\x85\x30\x0e\x9d\x3d\x6b\x5e\xa7\xe2\x6e\x3e\xcc\xee\xbd\x90\x1b\x34\xf5\xf5\xca\x6e\x1c\x29\xac\x9b\x1c\x96\x9b\x10\xc5\x6e\xf0\x2e\xe6\x0f\x22\xe0\x5e\xbc\x0a\xa2\xd8\xf9\x21\xc6\x96\x7f\x12\x7c\xd5\x92\xb9\x9c\x41\x64\x28\x7a\xbc\xcd\x28\xa4\x4c\xd7\x2a\xbe\x75\xed\x80\xfc\x9d\xc0\xa1\x73\x45\x77\xab\x35\x71\x51\xb6\x3c\x7c\xad\x12\x22\xbb\x4e\xe3\xf8\x81\x46\x31\x37\x32\x70\x55\xe5\x66\x9c\x52\x6a\x14\x8f\x04\xba\x56\x3a\x0c\x8b\x35\x97\x70\x54\x4a\x2c\x9e\xbb\x27\x64\x94\x80\x58\xf4\x3e\x3b\x21\x31\xa6\x2e\xad\xb3\x6f\x09\xb9\xf1\x9d\xa1\x6d\x46\x68\x67\x69\x5a\x7a\x96\xcb\x3b\x0a\x6e\x80\x3f\x0b\x7a\x7e\x58\x9e\x22\x27\x10\x6e\xb0\x21\xd9\xb0\x94\x50\x50\xb8\x66\x43\x72\x69\xbf\xc7\x4b\x90\xe6\x03\x7e\x1a\x9f\x0f\xba\x61\x10\x63\xdc\x4f\xfc\x11\x27\x41\x84\x91\x3f\x6d\x43\x1b\xf6\xbc\x40\xd6\x04\xf3\x86\xe4\x67\xe2\x46\xeb\x73\x02\x6f\x91\x0d\x4e\x62\x94\xbc\x69\x50\xe4\xbd\xca\xf2\x64\x9a\x07\x45\x9e\xe1\x98\xc7\x63\x22\xcb\xcc\x4a\x89\x1c\x68\xb7\x61\xb5\xdd\xb0\x23\xf2\x83\x18\xb8\x3f\xcb\x1d\xb7\x68\x5e\xe3\xc9\xca\x1a\xa7\x15\x35\xda\xad\x85\xb5\x1e\x9e\x2d\xae\xf5\xc7\x38\x90\x97\x6c\x48\xee\xdc\x94\xc7\x14\x06\x8c\x5c\xb3\x4b\x9f\xc3\xa5\x1f\x52\x18\xb3\x4b\x5f\xc0\x2d\x2b\x7a\xa4\x5c\x8f\xc6\x14\xee\xd8\x88\x0c\x89\xea\xc3\xb5\x1f\x0e\xb1\xdf\xbf\xd8\xa0\x5b\xe2\xec\x10\xc3\x3b\x0a\xb7\x17\x94\x06\xb7\x8b\x13\x63\x87\x1c\x63\x9e\x52\xf8\x95\x13\x72\x8b\xcf\x21\x3b\x22\xaf\x63\x98\xb8\xcb\x35\x76\xf1\x8c\xd9\x61\x49\xc0\x4b\xeb\x3f\x0b\x36\xd8\x21\xf6\xa7\x40\x4e\x67\xc8\xcd\xd1\xcc\x2b\x76\x44\xbe\x15\x00\xfb\x16\xe0\xd5\x12\xc0\xf0\x2e\xb8\x5a\x00\x67\x16\xc0\x3d\x5d\xa4\x1e\x87\x8b\x23\xfa\x0c\x1b\xdc\x2f\xab\xa4\x8b\x85\x88\x7e\xcd\xfb\xa0\x7d\xfe\x82\x76\x87\xe4\x26\xce\x7e\x04\x43\x22\xf2\x1f\x20\x62\x47\xc8\x47\x31\x59\x6f\xd3\xf9\xb7\x68\x4e\xab\x21\xdb\x33\x9a\x70\x76\x42\x42\x38\xa5\xd4\x47\xab\x3b\xf7\xc3\x2e\x12\xa3\xec\x7d\x2d\x8e\xc7\x35\xa5\x76\x43\x88\x38\x38\xcd\xd7\xfa\x28\x26\xa7\xb6\xdb\x22\x01\xc9\xe1\x58\x92\xd3\x54\x15\x66\xa9\x52\xff\x81\xf0\x90\x35\xf9\xed\xec\x26\x4b\xd2\x5f\xfd\x4e\xcd\x93\xaa\x77\x6a\x78\x3f\x75\xc0\x12\x75\xe0\x9f\xa6\xe0\xe3\x7e\xdd\x95\x53\x97\xdf\xaf\xc9\xcf\xea\x87\xfd\x95\xf7\xf5\x26\x89\x8b\xe4\x45\x61\xd2\x67\x43\x12\xf6\x51\x25\x99\xea\xd9\x8f\x5e\x78\x17\x14\x6f\x96\x8f\xfa\xec\x97\x82\x9b\xaa\xb6\xd6\xc6\x8a\xac\xbe\x93\x7b\xa7\xe6\xef\xe4\xde\x3b\x6d\x04\xf4\xfa\x6c\xac\x60\xa3\x12\xe8\x4d\x9f\x38\x95\xbf\x8b\x79\xd8\x43\x6f\xcb\x6b\xa7\x7b\xc7\x27\x84\xb2\xb4\xaf\xa9\xda\x7f\xf2\x51\x0e\xe4\x2f\x0f\x26\xb1\x4d\x1d\x64\xa9\x87\x3f\x13\x3e\xc2\x37\xed\x22\x18\xf5\x9d\x8f\xe4\x04\xb9\xd3\x3e\x4d\xaf\x97\x5c\xd7\x8e\x90\x91\x44\x3d\x42\x94\x2f\xfb\x35\x4f\x86\x0c\xfa\xff\xc1\xeb\x78\x4d\xb5\x78\xb7\xdb\x39\x95\xe0\xe5\x05\x4d\x8b\x08\x3b\xba\x29\x5d\x14\x04\xd0\x4c\x83\x71\xb1\xef\xc6\xfd\xba\xa0\x07\xe5\xf3\x73\xd0\xc7\xc1\x1e\x92\xeb\x3e\x5c\xf6\xad\xe4\xbd\x2b\x1f\xa7\xf1\x35\x6f\xfb\xac\xca\xb0\x7f\xdd\x07\x05\xed\xc7\x8f\x5b\xb4\xf9\xa4\xfd\xec\xf1\xee\x53\x30\x8c\xe8\xbd\x56\x57\x6f\xb6\x1f\xef\xb6\x9e\xed\x06\x9a\x3e\xc2\x6f\x4f\xa6\x2d\x90\x2c\x4d\x7e\xf2\x97\x81\x84\x11\xb9\x49\x24\xe6\x62\x74\x21\xf9\x68\x7b\x77\x67\xcb\xc5\x1c\x72\xc9\xcf\x76\xa7\x2d\x4a\x6d\xf2\xb4\x05\x9c\xc9\x4d\xb2\xbd\xbb\xf3\x57\xd2\x24\x49\x1a\x9a\x28\x49\x43\x13\xa1\xda\x67\xe7\x2f\xde\xdc\xa2\x8f\xda\x3b\xdb\xd3\x16\x44\x4c\x34\x89\xd8\x6b\xb7\xba\xdb\xc1\xe6\xb3\xec\xe4\xbb\xe7\x9f\x03\xbe\x49\x48\x7b\x67\xfb\x2f\x61\x0b\xef\xd8\x96\xdb\xc0\xe3\x20\x82\xb0\x1d\x24\xcd\xc7\xad\xd6\x5f\xa6\x49\xb6\xf6\xa2\x6e\x2b\x68\xd3\xd9\x0c\xee\x6a\xe7\xf8\xb6\x4f\x86\x64\xdc\x77\x22\xbf\xcf\x3f\x5b\x6a\xdd\xaf\xb7\xf5\x29\x01\x5b\x8f\xdd\xe8\xe6\xd5\x60\xb7\x85\x0c\xce\xe1\xea\x7a\x6d\xb9\xed\x66\x04\xe3\x44\xaf\x2e\xbb\xdb\x2a\xc0\xa3\xc6\xbe\x5f\x67\xf7\x59\xc0\x3f\x5e\xe4\x03\x5b\x0b\x62\x4b\x7b\x41\x90\xde\x5a\x0c\x6f\xb4\x20\x72\x3c\x5e\x38\xd0\x77\x16\x8e\xeb\xdd\x85\x93\xe3\xc9\x42\xe0\xa1\xa7\x8b\x87\xf5\xb3\xc5\x70\x42\xed\xd6\x22\xf3\xd4\x6e\xa3\x31\xa1\x5f\xef\xc7\xd1\xda\x53\xdd\x03\x72\xda\x07\xf5\xef\x7f\xb7\xe1\x2b\xd1\x76\x1a\xda\x0d\xd5\xfd\x4a\x0c\x68\x1a\x18\x1a\x58\x69\x7b\xb8\x82\xf8\x9d\xe2\x98\xe1\xdd\x51\x0a\x07\x2b\xda\xfa\x4a\x86\x64\xd8\x07\xb5\x79\x28\x2d\x5f\xe8\x6e\xc8\xb9\x0d\x75\xb4\x02\xfe\x81\x85\xef\xb5\x3c\x74\xa7\xc0\x49\x3c\xf9\x83\x39\xcf\x77\x6d\x5b\x6e\x3b\x5d\xf3\x1f\xae\xdc\xd0\x9e\xa8\x1f\xfb\x7f\x18\xbe\xed\xab\x25\xf6\x1f\xfb\xd0\x82\x33\x0a\x67\xfd\x6a\x29\xfe\xa8\x0f\x76\xa9\xff\xe8\xc3\xd7\xbe\x93\x7e\x36\xad\x5c\x74\xd4\x87\x2d\xf8\x93\x5b\x03\xed\x05\x56\x79\x6b\x61\x29\x6e\x2f\x2c\xc5\xc7\x0b\x4b\x71\x67\x61\x29\xee\x2e\x2c\xc5\x27\x0b\x4b\xf1\xe9\xc2\x52\x7c\xb6\xb0\x14\xdb\xad\xc5\xb5\xd8\x5e\xba\xc8\xd0\xde\x9a\xcd\xc8\x90\xec\x67\x7d\x9e\xeb\xf4\x90\xdc\x15\x63\x71\x56\x4a\xfe\x55\x24\x07\xa5\xe4\xab\xea\xe4\x93\x22\xd9\x4f\x93\xb7\x61\x48\x0e\x8b\xe4\xef\xde\x0c\xde\xf7\xd9\x59\x1f\x3e\xd9\x89\x7a\x1b\x41\xaf\x0f\xef\xfb\x14\x8e\x6b\x57\x43\x76\x0a\x63\x50\xfe\x5a\xbb\x3f\xbe\x42\x7d\xab\x08\x7a\x6c\x50\xd0\x33\x4a\xe1\xfc\xc2\x2e\xa0\x3c\xc8\xf4\x8b\xfe\x1f\x86\xc6\xfd\xb2\x62\xcf\x38\xdf\xad\xbf\x4f\x4e\x53\xe7\xad\xf4\xe1\x9e\xdf\xfd\x3a\x6f\x01\xb4\x0f\xcc\x79\xdd\xa4\x3c\xc8\xc4\xbb\x40\xc3\x00\x31\x2c\xe7\x09\x52\x4b\xf0\xc4\x9e\xeb\xc7\x7d\xd8\xe8\x03\x91\x4c\x53\x3f\x1c\xba\x63\xbf\x08\x09\xf1\x09\x2d\x5d\x27\x2e\x39\x0b\x27\x81\x89\xfc\x8b\x4b\x14\x5a\xf2\x34\x42\x73\x0f\xd3\x3f\xa5\xe9\xf1\xf5\xb5\x54\x26\x4b\x3d\x4d\x19\x8a\xde\x02\x2f\xd1\xeb\x83\xf4\x43\xe1\x78\x09\x9b\xd4\x07\x8f\x8f\xc7\xa3\xc8\x85\x65\x7f\x84\xef\x24\x02\xbe\x71\xd8\x72\x0f\x9b\x14\xce\x40\x07\xe4\x4b\x1f\x5d\x12\x27\x2e\x6c\xcc\x9b\x7e\xf5\x65\x8c\x81\xb3\xd5\xf7\x41\xb2\x36\x2b\xdc\x0f\x3b\xa5\xe8\x04\x7e\x78\x0d\x27\xc1\xba\x6e\x34\x64\xb7\x15\xe8\xff\x2f\x77\xef\xbe\xdd\x36\x8e\xf4\x01\xbe\x8a\xc2\xd1\xf6\x00\xed\x92\x22\xd9\xce\x8d\x69\x1e\x1d\xc7\x76\x12\x27\x4e\x9c\xc4\x76\xec\x64\x26\x5f\x0e\x40\x42\x36\x65\x5e\x14\xde\x6c\x25\xe1\xbe\xc6\xfe\xbb\xcf\xb2\xfb\x62\x7b\x50\x00\x6f\x12\x29\x3b\x3d\x3d\xdf\x37\xfb\x9d\xee\x13\x53\x04\x08\x82\x40\xa1\x50\x55\xa8\xfa\xd5\xcf\x9f\x62\x82\xd7\x9b\xe6\x96\x39\xc6\xdc\x08\x43\x7e\x9e\xe7\xf0\xb9\x73\x72\xd9\xb1\x14\xf5\x8f\x81\x9d\xca\xbf\xa7\x90\x99\x11\xc4\x66\x30\x8c\x81\x9d\xc9\x3b\x67\xc0\x6d\xd9\x8a\x0d\xfc\x48\xfe\x3d\x02\x34\x62\xe5\x14\x5e\x76\xd2\xe4\x1e\x23\xc8\xcc\x36\xce\x99\x32\x85\xc0\xfb\x76\x39\x6a\x98\x44\xae\x4f\x68\x0e\xdf\xa6\x1a\x1a\xe0\xda\x80\x87\xa3\xed\xc7\xe2\x01\x0e\xbb\x63\x00\x62\x08\xe2\x8f\x4b\x03\xb6\x1e\xea\x6b\xdf\x50\xe2\x8d\x9c\x74\x03\x79\xe6\x17\x0a\x6f\xda\x5f\xf2\xc7\x48\x9b\x86\xde\x4f\xdb\x05\xd6\x42\x9a\x62\xe8\xfc\xac\x5c\x59\x19\xba\xae\xd4\x54\x29\x76\x5f\xfc\x1c\x4d\xd2\x0d\xb2\x93\xa8\x6b\xba\x41\x92\x0d\xa3\x67\x50\x6a\x62\x52\x22\x1b\x04\xa8\x30\x87\x23\x62\x18\xa0\x3e\x1d\xbe\x4d\xa9\xc2\x8a\x7d\xb6\x7e\x13\x78\x04\x44\xff\x8d\xe8\xcf\x9f\x8f\xe8\xc6\xa3\xc1\xff\x0c\xab\x5d\xe2\x8b\x8f\xf2\x5c\x4f\xe1\xf3\xb6\xd1\xbd\x57\xc2\x55\xfe\xf6\xdb\xbd\x3a\x5e\x65\x81\x5e\xa9\x00\x2b\x73\x78\xd7\x25\xc4\x3e\x9f\x92\x80\x4e\xc6\xe6\xa8\xb0\x69\x45\xb7\x05\xa1\x6d\x2d\x27\xfb\x7b\xf0\x64\x23\x59\xfa\xce\x27\xa3\xe2\xd6\x76\xc5\xe1\xcb\x7b\xe5\xe7\x8e\x1f\x8c\x8b\x7b\xe5\xee\x32\x7e\x5c\xde\x2b\x77\x98\xcd\xf1\x66\x71\xaf\xdc\x65\x36\xb7\xb7\x8a\x7b\xe5\x4e\xb3\xf9\xa8\xbc\x57\x03\x57\x1c\x6d\x6f\x24\x2b\xf9\x08\xb7\xb6\x37\xd0\x93\xe1\xc5\x1d\xb4\x90\x8f\xd3\xb5\x60\x9f\x3d\x29\x58\x47\x1b\x64\x46\x5e\x4c\x21\x82\x6d\x3a\xd0\x57\xe3\xd1\x88\x6e\x14\x77\x47\x52\x58\x85\x4f\x9d\xaf\xfb\x28\x27\x62\x63\x46\xde\x29\xc9\x02\x73\x6e\xbf\xee\x14\x3f\x57\x66\x69\x6b\x99\x14\xd5\xc4\x6e\x3e\x31\x37\x1f\x2f\x13\xe5\xb2\x2c\xba\x35\x5a\x16\x46\xc7\xcb\xc8\x9a\xa3\x62\x96\x96\x81\x32\x97\x41\x31\x47\xcb\x00\x98\xe3\xd5\xf9\x58\x99\x0c\x94\x3b\x03\x6e\xfd\x6f\x96\x6e\x20\x6a\xfd\x3e\x3c\x6f\x1f\x4b\xf1\xe3\x7f\x89\x02\x01\x09\xbf\xf5\x44\x7e\x46\x5e\x6b\x15\x2e\xb5\x02\xae\x23\x33\xc6\x9b\x7f\x58\xe9\xcf\x9f\x0b\xc4\x1a\xf9\xc3\x1a\xd1\x4a\xed\xc4\xdc\x44\x91\x54\x32\x83\x32\xd7\x2a\x27\xe9\xc6\x98\x42\x62\x25\x03\x34\xed\x08\xde\xed\x1c\x82\x6b\x10\xdf\x87\x4c\x31\xd2\x5e\x19\x29\x6f\xd5\xcb\x05\x47\xbd\x5c\xaa\xda\x15\xaa\x0f\xde\x8e\x86\x1c\x50\xcf\x96\x1d\x57\xee\x02\x78\x5f\x0c\xb9\x7c\x60\x4c\xa1\xc8\xe4\x87\xb7\x99\xaa\x5e\xca\x1e\x4a\x3f\x1e\x8f\x46\xbf\xa7\x1b\xdb\xbf\xdb\x1b\xee\x90\x6d\x10\x77\xc8\x25\xfb\xa5\x39\xb0\x96\xee\x40\x02\x42\xca\x60\x29\x27\x91\x15\x50\xf8\xc1\x62\x33\x1a\x7c\x9c\x4a\x8d\x88\x8f\xa5\xb2\x55\x99\x20\x12\xec\xc8\x18\xa3\xdd\x58\x4c\x73\xb0\xb9\xf2\x89\x66\xbc\xdd\x66\xcf\xc2\x9c\x82\xab\x2b\xd9\x6d\x95\x48\xc0\x25\x57\xda\xa4\xf7\xb7\x7e\x8e\x72\x0a\x21\x5f\x23\x48\x46\x4f\xbb\xd6\xac\xc0\xfe\x4b\x46\x4a\x04\xdd\x18\xaf\x04\x92\x7f\x9a\x82\xaa\x40\x12\xcb\xc5\x8b\x88\x93\xad\xdf\x93\xc1\x26\x5d\x39\xed\xae\xd5\xb6\xe5\xbf\xa5\x45\xb6\xb9\x1c\xd2\xc1\x8c\x3c\x9b\xa2\x5f\xf6\xd2\xc2\xd0\x25\xe3\xb2\xe4\xe1\x52\xc9\x66\x59\xf2\x68\xa9\x64\xab\x2c\x79\xbc\x54\xb2\x5d\x96\x3c\x59\x2a\x79\x50\x96\x54\x4b\x49\x17\x3d\x94\x45\x4b\x4b\x08\x45\xfc\x29\xef\x16\xf1\x17\xe8\x31\xfe\xc7\x68\x12\x98\xa3\x3f\x16\xa8\x76\x4f\x22\xd4\xba\xf9\x9a\xa7\x96\x77\x97\x5d\x32\xe5\x98\xee\xb2\x58\x88\xa8\x27\xc4\xbc\x5b\xaf\xe6\x5c\xe9\xa4\x7a\x19\xed\x94\x57\x8b\xca\x5c\xe2\xf1\x36\x09\x50\xc3\x50\x07\x83\x47\xe3\x27\xe3\x87\x5b\x34\x87\x8c\xaf\xc3\x7a\x90\x52\xe6\xef\xc1\xc6\x43\xb1\xfd\x7b\x84\x88\xfc\xc9\x86\xc8\x29\x38\x9d\x9d\x3b\x20\x19\x57\xda\xa0\xee\xd2\x55\x79\x75\x54\x5e\xed\x57\xdd\xec\x77\x50\xb1\x85\x52\x73\x01\xe1\xed\x71\x32\x23\x31\x57\x4f\x6d\xcc\x88\xa3\x2e\x07\x09\xbd\xff\x50\x6c\xe3\x72\xf0\x79\xa7\x9f\x9b\x27\x69\x73\x23\x41\xfd\xaa\x2f\x9f\xdc\x63\xe8\xc3\xcc\x2c\x79\x31\x90\x1f\x97\x52\xcc\xb7\x8f\xa5\x05\x78\x4a\x0a\x36\xad\x00\x89\x95\x57\x60\xf9\x80\x5d\x43\x56\xb2\x41\x3f\xe9\x52\x3a\x71\x4d\x96\x53\xb8\x5c\x33\xff\xbb\xc4\xe7\xe8\x65\x13\x72\x8c\x83\x89\x39\x16\x53\xc0\x6c\x8e\x17\x6d\x4f\x2e\x2d\xe6\x71\xb9\x80\x0a\x09\x6b\xdb\x5c\x6e\x5c\xb7\x0a\xd5\x84\xe0\x4f\x9c\x10\x7d\x75\xa4\xaf\x46\xe5\x71\xd2\xd6\xaf\x37\x33\xaa\x3d\xbe\x79\xd7\xc7\x47\x8d\xc7\xc6\xd5\x63\x97\x1c\xc6\x63\x85\x9a\xd9\x64\x35\x58\xb4\x59\x2b\x19\x35\x4a\x46\xb5\x92\xa5\xe6\x6a\x25\x5b\x8d\x92\xad\x5a\xc9\x76\xa3\x64\xbb\x56\xf2\xa0\x51\xf2\xa0\x56\xf2\xb0\x51\xf2\xb0\x56\xf2\xa8\x51\xf2\xa8\x56\xf2\xb8\x51\xf2\xb8\x56\xf2\xa4\x51\xf2\x44\x95\x2c\x31\x24\xf5\x41\xea\x5b\xd1\x1c\xce\xdb\xbd\x2a\x2f\x38\x8c\xb7\x94\x25\x25\x87\x6b\xde\x19\xe2\xb3\xd7\x1a\x76\x30\xe7\x08\xd6\x17\x54\xc6\x66\xd7\x8c\x80\xcd\xcc\x5b\x1e\x88\xa8\x14\x0d\x82\x2a\x6b\x61\x00\xec\xbb\x02\x0b\x5c\x70\xeb\x64\x0a\x37\x6b\x16\xc5\x57\xb2\x48\x41\xa7\x2d\x8c\x8a\xac\x85\x01\x85\xcc\x9c\x91\x6b\x0e\x88\x38\xa5\x92\x13\xbf\x9c\xc2\xa3\x4d\xf1\x40\x81\xda\x60\x3a\xc3\x02\x73\xe1\xcd\x94\x20\x58\x3b\x2d\xb2\x1b\x2e\xf8\x72\x7d\x95\xe5\x70\xc1\x89\x5c\x6f\xca\x99\x22\xa7\xb0\xdf\xc9\xce\x90\x0b\x0d\x2e\x25\xc7\xce\x29\x5c\xf1\x5b\xe2\xfc\x83\xe5\x08\x40\xd8\xe1\x9d\x39\xca\xe5\x03\xc6\xf1\x65\x98\x7a\x4e\x2f\x08\x93\x1e\x17\x3d\xe1\xcf\x93\x85\x41\xcd\x19\xb9\xe2\xe0\x25\xc4\x38\x8b\xc2\xe0\xa2\x77\x70\x7c\xf4\xf8\xe1\x68\xdc\x9b\x86\x91\xcf\x12\x83\x82\x5f\x80\xb1\x72\x8b\x75\x66\x43\xab\xdb\x35\x52\x39\xa2\x42\x0e\x4b\x02\xdc\x36\x19\x66\xd1\x94\xa3\x11\x01\x7f\x6f\xda\xc0\x3f\x9a\x88\xd1\x37\x5b\xb7\x1b\xfc\xe0\x53\x53\x00\xbf\x90\x6d\xf8\xf2\xf1\x73\x65\x05\xdb\xe5\x96\x02\x0b\x2d\xcf\x9a\x76\x6d\x32\x4d\x71\xbe\xee\x8d\x0a\xb8\xcf\xf2\x78\x6a\x5a\xa0\x91\xea\x43\xac\x12\x9d\xb4\x9e\xdb\x6b\xa6\xb2\x21\xc3\x01\xb7\xd6\xe2\x9e\x22\x5a\x6a\x23\x6f\xd8\x6d\x89\xd1\xc4\xcd\xdc\x8d\x7e\x35\x29\xda\x5c\x04\x8e\x1b\x5c\xfc\x0b\x19\xd1\x3a\xf2\x95\xbd\xd3\x51\x6d\x7a\x8c\x9c\xda\x70\x94\xe6\xb7\xea\x4e\x65\xa8\x2b\xef\xad\x00\xc4\xb6\x80\xc1\x56\xc6\xc2\x29\x23\xbb\x1c\x3b\x73\xcc\x2b\x9c\xd6\xa3\xee\xbd\xb3\xdd\x22\x69\x40\x54\x0b\xe5\xc1\xc3\xf4\x04\x8a\xd8\x3e\x01\x07\x5c\x3b\x89\x73\x8b\x24\xa9\xb5\xc7\x1a\xf9\x1c\x03\xfa\x23\x20\xfb\x01\x49\x52\xb2\xc7\x12\x31\x0c\xc2\x6b\xa2\x7c\xa9\x28\x7c\xe0\xf5\x28\x34\x9d\xff\x76\x57\x7e\x76\x18\x19\xe0\x4c\x29\x9c\xb7\xf2\xbc\xaf\xe4\x38\x85\x1f\x1f\x4c\x4d\x71\xc7\xc5\xc5\x49\x71\x51\xb8\x23\xa1\xff\xcd\xab\xa9\x76\xc8\xc9\xe1\x84\x77\x66\x29\x5a\x4d\x1b\xa4\x91\x3c\x74\x96\x9f\x68\xc8\x0a\x28\x80\xa4\x51\x27\x29\xea\xb8\xe8\xc8\x55\x86\x45\xd4\xeb\x88\xa2\x4e\x88\x19\xe1\x6b\x99\x86\xaa\x3a\x69\x51\x67\x5a\x87\xe8\xd4\x21\xf7\x92\x7b\x30\x0d\x2b\x72\x41\x82\x02\x7c\x1b\x98\x06\x18\x79\xcb\xad\x43\xf2\x8f\x03\x32\xe3\x92\x35\x1a\x06\xdc\x1b\xeb\xf5\x48\xbf\x50\x38\xe5\x98\x23\xd6\x30\x24\x5f\x90\xff\x9e\x99\x7b\x08\x78\xa6\x93\xc1\xce\xcc\xb7\x5c\xb2\x07\xbc\x99\xc3\x61\xd7\x1e\x72\x44\x76\x24\xf3\x87\x1d\x25\xfe\x63\xda\x07\xa6\x8c\xb3\xbc\xfa\x96\x64\xc8\xcb\x53\x5f\x5e\x7d\x89\x94\x99\x2f\xd5\x13\x8c\xc2\xa5\x54\x48\x28\x32\xc5\x5d\x16\xfc\x1d\xf9\xa1\x1b\xf4\x92\x4b\xd1\x9b\xb3\x38\x31\xf0\x4b\x31\x92\x7c\xaf\x95\x04\x66\x82\xbc\x97\x7c\x9a\xae\xe1\xab\x97\x0a\x87\xf6\x8c\xb7\x5a\x99\xed\x7d\xb4\x32\x1f\x29\xdb\xe7\x39\xa4\x2d\xae\x61\xc9\xaa\xf3\xe4\xbd\x31\xdc\x1b\xad\xfa\x44\xc9\xdb\xe3\x55\x8f\xc9\x7b\x23\xac\xbd\xe2\x2b\x25\xef\x8f\xd1\x4f\x0a\xea\x88\xac\x92\xe7\x5e\x4b\x52\xe0\x54\x72\x5e\x26\x39\x2f\x82\xf0\x8a\x3c\x87\xef\xed\xdf\xc1\x67\x4f\x8b\x7d\x06\x41\x04\xb8\x8b\x43\xf2\xce\x13\xb2\x2f\x76\xe8\xcf\x3d\x91\x88\x1e\x73\x24\x4b\xc3\x01\x2e\xe3\xca\xcc\x68\xc8\x27\x97\x1a\xcf\xff\x8c\x4b\x71\xdb\x94\xcf\xbe\xd1\x1c\xa4\xc7\x22\xd1\x8b\xc4\xb7\x14\x59\x28\xcd\xe1\x55\x3b\x65\xa0\xc5\xd8\x56\x1a\xfb\x31\x06\x6f\xb0\x53\x34\x26\xf3\x23\xe5\xea\x77\x56\x10\xc1\x8d\x4b\x3c\x72\xc2\x61\x6d\x7c\xfe\x57\x72\xca\x51\x3a\x88\x24\xbd\x62\x62\xcf\xb4\xb9\x8f\x09\xdc\xc8\xbf\x23\x31\xee\x71\x92\x0c\xf9\x39\x5e\x08\xbc\xd8\xe1\x72\x04\xcf\xa5\xdc\x7a\xc8\x41\x5e\x82\x8d\x7e\x13\xe8\xe1\xde\xb9\xab\x2f\xf0\x17\xea\x77\x51\x4e\xe1\x65\x37\x9b\x4c\x3a\xf5\xed\x5d\xf2\x52\x0a\xa1\xe3\xcd\xdf\x23\x10\x4b\xae\xaa\x8c\x13\x21\xa7\x7b\xbc\xf9\xbb\xec\xdf\x78\x30\xa6\x1b\x52\xcd\x4f\x87\x2c\xa4\xf2\x47\x24\x07\x8b\x2b\x73\xf8\x78\x13\x18\xdd\x18\x53\xb4\x68\xbc\x98\x02\x83\xf1\xa6\x54\xe0\x2b\xad\xd2\xd5\x5a\xa5\x0b\xb6\xbc\xfa\x2c\xbf\x94\x7d\x54\x8a\xa5\xbc\xb7\x4c\x8c\x62\xe3\xd1\xef\xd1\x32\x25\x8a\x0d\xdc\xd3\xdf\xb7\x0b\x02\x2b\xa9\x2f\x56\x34\x12\x75\xe0\x21\xe8\x46\xa9\x6a\x6f\x9b\x81\x35\x7e\x00\x91\x85\xe9\xe2\x0a\xb4\xcc\x55\x74\xd1\xad\xa2\x1e\x6a\x9b\xdd\xf5\x36\x8b\x7a\xa8\x9c\xae\xa9\x38\x6e\xa8\x23\x09\xe0\x54\x6c\x15\x7a\x89\xfc\x1e\x49\x10\x8e\xbe\x5c\x51\x38\xaa\x67\xc6\xeb\x9f\x19\x99\x81\xb5\x29\xbf\x6f\x73\x5d\x6f\x74\xa5\x75\x43\x80\x23\x30\x86\xc8\x7a\xd4\x5e\xa9\x42\x5c\x5d\x53\x0b\xd3\xb0\xad\xd1\xcf\xdf\x73\x49\x4a\x81\x54\x0f\xd0\xa2\xfe\xe6\x96\xba\x5b\xb5\xba\xcf\xf8\x9a\x84\x07\x17\xbc\x48\x78\x50\x6a\xc6\x02\x12\x3a\x49\x4c\x6c\x28\xc0\x61\x44\x06\xfe\xbc\x43\x6f\x79\x26\x55\xbc\xf3\x29\xa8\x17\x8f\x61\x2c\x7f\x60\xc3\x9b\xc5\x59\x74\x0e\xef\xd6\x28\x3d\xe3\x42\xe9\x79\xd1\xb5\x61\x05\x83\xe2\xa8\xba\xc2\x78\x2f\xc6\x24\x29\xbf\xf3\xe3\xba\xc7\xaf\x5a\x1f\xdf\xaa\x3d\xfe\x69\xe9\x71\x56\x5a\x10\x3b\x87\xaf\xd5\xfb\x60\xaf\x23\x2c\x5c\xa5\x52\xc6\x90\x84\x12\x07\x6f\x72\x24\xc5\x81\xef\x80\x81\x1d\x33\x4a\xcd\x23\x82\x97\xdf\x29\xe0\x8d\x9c\xa2\xe5\x74\xe6\x82\xda\xe8\x99\xe4\x31\x4f\xbb\x23\xa7\xbf\x12\x06\x3f\x58\x28\x37\x9f\xe7\x1c\xe1\x38\x97\xb7\xb8\x5a\x0d\x12\x59\xa2\x36\x51\xc5\xfc\x0d\x96\x26\x30\x52\x91\x8e\xcb\x4b\x4d\x35\xf4\xad\xf2\x6f\x5d\xd2\xc9\x8b\xf2\x45\x92\x37\x7c\x3e\xd3\xb6\x10\xbc\x9a\xb8\xf6\x4e\xee\x06\x4f\x4b\xa3\x28\x68\x2f\xf3\xa7\x15\xa7\x22\x68\x67\xc2\x7a\x72\x78\x2e\xa7\x44\xde\x64\xf2\xa2\x46\x50\xa9\x65\x53\x94\x4f\x52\x3a\x60\x52\x5e\x4e\x36\x54\x36\xd9\x4e\x98\xf0\x60\xd8\x9f\x44\x2a\x88\x39\x45\x5f\x34\x65\xec\x6a\x81\x0c\x64\x43\xf6\x6d\x09\x28\x10\x27\x72\x21\x27\xc8\xad\xa1\x1f\x80\x14\xb6\x6a\x05\xa5\xe4\xc9\x6a\x90\x5a\x4a\xea\xaa\x8c\xed\x98\x43\x14\x16\x89\x86\x6e\x6b\x8a\x5f\x45\xf1\xb5\x42\x5b\x6d\x36\x51\xc6\x52\xd4\x63\x44\xaf\x6d\x50\xc3\x15\xa9\xf1\x78\xc7\x49\x4a\x29\x9d\x60\x4b\x4a\xdf\x8b\x90\xf2\xca\x86\xd3\x0a\x62\xa8\xde\x1b\x44\x34\x74\x87\x0c\xa6\x18\xd1\xd7\x98\x67\xd7\x9c\x2a\x63\x83\xad\xa4\xd9\x19\x05\xb6\x30\x43\x60\xdf\xf1\x5e\x08\x48\xd4\x79\xc3\x9d\x98\xe3\x08\xc5\x78\x64\xed\x21\x6a\x57\xd6\xa9\xa9\xff\x31\x9a\x8c\x4c\xdc\x51\x75\x28\xa7\x63\xed\x92\x04\x71\xd0\xba\x66\x73\x32\x23\x1f\x39\xcc\x48\x06\x0f\x47\xe0\x51\x88\xa4\x86\xfe\x42\xdd\xd9\xdc\x56\x77\xf2\x4a\x1f\x52\xdf\x31\x33\x9d\x21\x97\xbd\x76\x30\xef\x6f\xc1\xbb\xb1\x7b\x4f\x95\x73\x3b\xbe\xb7\xd6\xf5\x76\x9e\xd3\x8a\xdf\xb1\x3c\x0f\x92\x37\xa2\x98\x52\x3a\x57\x48\xa9\x61\xf2\x86\x9b\xdf\x38\x78\x8a\xfe\x56\x3a\xd8\x57\x1d\xec\x17\x98\xec\xaf\x79\x7b\x68\xe2\x1a\x35\x48\xd4\x57\x94\x56\x85\x26\x5a\x07\x32\x51\x90\x0c\x40\xa8\xb4\x50\x39\x85\x20\xd6\x99\x5c\xa2\xd8\xfa\x18\x41\x12\x5b\x9f\x22\x10\x71\xa7\x43\xc6\x07\x33\x1a\xb2\x0f\x1b\x24\x18\x60\x8e\x51\xdb\x8c\x10\x56\x3e\x52\x88\xf4\xc0\xf7\xa5\xbc\xba\x0f\x0c\xd1\x42\x73\x0a\x69\x6c\xbd\x88\x80\xc5\xd6\xbb\x08\xec\xb8\x8d\x3d\xec\x12\x16\xc3\x78\x34\xc6\xc9\xff\xf9\x13\x7f\x3e\x7c\xa2\x0c\xcb\x05\x8f\x47\xbc\x6f\x2c\xd9\xde\xc2\x4c\x5d\xba\xde\xf6\x03\xfc\x35\x49\x36\xc6\xa6\xb2\x26\xa7\xb1\x4a\xcd\x55\xdb\xf0\x52\x3a\x19\xa4\x66\x5a\x81\xe9\x51\x70\xe3\x6e\x53\xbe\x6c\xf6\x21\xbe\x7e\x32\x23\x76\x0c\xd8\x26\x46\x86\x6b\x32\xb3\xe3\x82\x4e\xc3\x78\x2d\x02\xb2\xc0\x60\x59\xa1\x1c\x6a\xdb\xf2\xdd\x22\xb4\xc4\x15\x83\x14\xd0\x48\xa5\x35\xd4\xda\xf4\xcd\x49\x02\x45\xa2\x0b\x95\xd6\x3a\xa1\x7f\x94\x0f\x05\x35\x40\x6e\x97\xd8\x18\x0c\x11\x03\x43\x28\x64\x0a\xd3\x78\x7d\xfa\x9b\x7a\xaa\x6f\x5d\x88\xe9\xf3\xe2\x4e\xf5\xbb\x48\x6c\xa5\x8e\xf0\xdc\x18\x6c\xd4\x6d\xe5\xd7\xb9\x95\x9b\x70\xf1\x65\x07\x64\x1a\x03\x43\x62\x18\xb2\x0f\x03\xe2\x6e\x60\xd2\x40\x8c\x46\xa4\x45\xd6\xed\x21\x07\xb7\x1d\x0e\x1d\x39\xb4\xaa\x65\xd7\xea\x5c\x90\x50\x0e\xbf\xc2\x18\x4c\xf5\xc9\x40\xa1\xcc\xff\x68\x1b\x5c\x86\xe7\x99\xa5\x62\x0f\x53\xeb\x94\x11\x44\x41\xc7\xb7\x2b\xf5\xbc\xbe\x5e\xa6\x88\x73\xb6\xdc\x42\x39\xd2\x21\x99\x4a\xe5\x18\xc7\xda\xd5\x4e\x35\x71\x6c\xcd\x48\x07\x45\x09\xeb\x07\x3b\x94\x2a\x5b\x44\x81\x7d\x32\x03\x60\x63\xb9\x0c\xe7\x82\x02\x67\xfa\x3e\x17\xf2\xd6\xbb\x84\x82\xbd\x2b\x95\xc9\x40\xdd\xcf\x97\x93\xf3\x2a\xea\x7c\x5c\x62\xca\xd7\x34\x4c\x04\xc6\x8f\x2a\xed\x43\x2d\xab\xcd\x11\xa2\xc1\x33\x3a\xc1\x81\x13\x43\x7b\x17\xc4\x90\x33\x0c\x65\x4c\x74\x6c\x06\x85\x40\x7e\x9e\xac\x8f\xa6\xfe\xd5\xfa\x01\xca\xdd\x51\x0c\x8f\x97\x9f\x78\xf2\xb8\xed\x01\x76\x58\x3c\xb0\x59\x7b\xc0\x23\xbc\xaa\xf1\x49\xb6\x2b\xe4\xd5\x18\x8e\x48\x04\x23\x59\xa5\x58\xa3\x9d\x35\xb1\xcd\xf1\xa8\x1c\x00\x14\xb8\x90\xeb\x21\x2f\x83\x20\xa6\xe0\xc5\x56\x03\xde\x9f\x09\x39\x41\x7f\x06\xab\xfe\x13\xd3\x58\xf5\x53\x29\x63\x64\xf1\x2a\x24\xb6\xfe\xe7\xb5\x0d\x23\x58\x93\xd0\x42\x67\x6b\x6c\xc9\xb4\xe3\x92\x60\x03\x79\x09\xb6\xe4\xc5\x70\xed\x52\xaa\xb3\x5f\x44\xb4\x84\xf0\xd6\xb8\xd3\x4e\x5c\x22\x4a\x67\x31\x85\x2b\x4e\x2a\x93\xb4\x93\x46\xe8\xdd\x57\xda\xa4\x29\x85\x7e\xbc\x36\x22\x90\x39\xe6\x45\x8a\x8e\x78\x0a\x9b\x29\x6e\x8f\xda\xd8\xd4\x51\x1b\x97\xb1\xc6\xe5\xbd\xb8\xb5\x59\x92\x58\x88\x37\x71\x4e\x41\x6e\x3f\x7e\xac\xb7\x9f\x98\xe6\x95\x53\xe7\x7c\xa9\x19\xd1\x8a\x1b\xa4\xb6\x80\x1d\x4e\x30\x57\x33\x85\x54\x5e\x8b\x21\x3b\xc3\xd6\xa3\x55\x01\x6e\x97\xbc\xe6\xb0\x2f\xf5\xc1\x74\x19\xf1\x59\x0c\xe3\x21\x3f\xd7\x22\xdc\x9b\x29\xa9\xe7\x3f\x88\x86\xfd\x89\x2a\xc7\xbd\x8b\xd4\xf6\x66\x01\x3f\x62\x73\x46\xfa\xb1\x54\x97\x86\x31\x1e\x5a\xe0\x4f\x06\xe8\xc8\x99\x37\xac\x08\xd8\xcf\xa7\x89\xea\x26\x3f\xc2\x6e\x62\xa7\xd9\xff\x54\x77\xd9\x59\xd5\x5d\x76\x56\x13\xf7\x99\x96\x63\x6b\x5d\xd5\xa6\x54\x27\x96\xdd\x75\x2d\xe2\xa9\x0e\xbe\x9c\x82\x0d\x09\xa5\xf8\x56\x1c\x7b\x73\xc1\x89\x57\xeb\x50\xfd\xbd\xac\xf9\x5e\xb7\xf9\xde\x2d\x73\xf9\x91\x8b\x18\x9c\xb8\xf6\xcc\x45\x0c\x87\xb5\xd1\xc3\xa7\xd5\xa0\x5f\xc4\xb0\xc3\x9b\xa3\xbe\xdd\x68\x8e\x9d\xaa\x77\xa2\xc7\xe4\x90\x9d\xd6\xe4\xd2\x95\x6a\x17\x31\xec\xf1\x66\xad\x87\xcd\x5a\xc7\x8d\xc6\x8e\xcb\x6a\x8f\x56\xab\x95\x8d\x55\xb5\x1e\x9b\x6a\xdb\x59\x99\xf3\x23\x22\x86\x19\xea\x86\xf2\xcf\x4c\xcf\x3b\x53\xc8\xc7\x35\x33\xed\x0e\x8e\x01\x7e\x3f\x8e\x4e\xa5\x7c\x14\x90\xb8\x15\xe7\xda\x21\xc5\xe8\xa8\xf3\x34\x9d\x31\x47\x0d\xa5\xfa\x0d\xe5\x49\x9b\x2e\x71\x62\x68\x9e\xd6\xcd\xc8\xbe\x3e\xfb\x46\xbd\x70\x85\xaa\x6c\x2b\x1c\xda\x68\xec\x53\x10\x3c\x47\x66\x62\x85\x43\xa6\x0f\xee\xea\xd1\x78\x53\x8b\xc4\x75\xba\x52\x94\x23\x3f\x5a\x6a\x61\xb1\x5c\xc9\xdc\xba\x71\x49\x6d\x31\x37\x5f\xa6\xcf\x19\xa7\xc0\xa9\xf2\xea\x5d\x31\xd1\x62\x35\x7d\x64\x28\x5f\x19\x83\x27\x99\x65\xdc\x6e\x82\xb5\x71\xc0\xd8\xa9\xb2\x25\x1f\x21\x8a\x30\x3b\x43\x94\xe7\x18\x61\x84\xb3\xa7\xd5\xe9\x5c\x31\x9d\x81\x9c\x4e\xa8\x11\x4b\x42\x21\x33\x6d\xa8\x88\x96\x2d\x93\xac\x5c\xed\x68\xb5\x8f\x1a\x14\xab\x0f\x37\x73\x58\xb4\xf5\x0f\xcd\xa4\xcb\x08\xa6\x7e\xac\x61\xca\xe3\x1c\x6e\xe2\x75\x10\x02\xf5\x50\x6b\xa5\x27\xce\xc8\x2b\x0e\x18\xb2\x1d\x0d\xd9\x76\x99\x5b\x6c\x29\x86\xb1\x6f\x2e\xf0\x1d\x5f\x29\xb0\x6d\xf3\x1a\xaf\xb7\x29\xf0\x43\xf3\x53\x4a\x8c\xdd\xd2\x60\x1f\xa7\xdc\x77\x13\x34\x4c\xcb\xdd\x05\x7a\xc7\xea\xd4\xa9\xe7\xc6\x58\xbe\x10\x49\x0f\xb3\xc0\x0e\x8d\x22\x00\xbf\x4c\x54\xb6\x1c\xf0\x79\x68\x86\x69\x19\x04\x59\x45\x7d\x86\x53\xf8\x80\xf1\xbc\xdf\xa7\xca\x57\x19\x3e\x70\xa9\x5d\x9f\xea\x18\x49\x7b\x0a\x87\x42\xdd\xa8\x85\xf4\x2a\x5a\xb3\x2d\x0c\xc5\x8c\x71\x83\x40\xe9\xad\x88\x83\x4d\x36\x8c\xbf\xdd\x2f\x9c\xf6\xef\x1b\x1b\x92\xee\xcc\x67\xe9\x6a\x9f\xe2\x9c\x96\x61\xd4\x0f\x4d\x25\x88\x07\x75\x17\xeb\x48\x75\x43\xe5\x06\x20\xe9\x14\x42\xe4\x9d\xee\x90\xcf\xc0\x45\x2a\x91\xdd\xff\xca\xab\xd0\x61\xb5\xf6\x31\xf6\x15\x15\x60\xa9\x57\x3a\x55\x83\x3f\xd8\x2e\x9e\xca\x1f\x98\x5e\x8a\xa1\xd0\xa9\x12\x3a\x58\x5f\x6e\xca\x6c\xdb\xdc\x25\x37\x1c\x0f\x90\xa4\x9e\x25\xf5\x2a\x7b\x5f\xce\x8c\x97\xe6\x75\x70\x12\x24\xfc\x7a\x37\x77\xc9\x11\x07\x81\xfa\x6b\x11\x07\x8f\x43\xbb\x12\x4e\xbb\x85\x30\x8f\x6c\xd8\x9f\xb4\x76\xa6\x38\x97\x53\xfb\xae\x1c\x58\x8c\x64\x28\xbb\x47\x7c\x8b\xc1\xa5\xe5\xcb\x95\x75\x61\xf9\x72\x65\xcd\xe5\x9f\x63\xb8\x96\x37\x8f\x60\x21\x7f\x9d\xc1\x8d\x5e\xe5\x6f\xa7\xe4\x5a\x32\x9e\xfd\xea\xf7\x42\xfe\xd6\x2e\x06\xf3\xc2\xc5\xe0\xa2\x74\x31\xb8\x81\xfd\x55\x7f\x02\xe4\x50\xd7\xb0\xa0\x0d\xa7\x82\x05\xc5\x25\x77\x9d\x90\xcb\x9a\x4b\xc1\x75\xe9\x52\x50\x1f\xc0\x68\xc8\x0f\x73\x35\x9b\x73\x21\x89\xea\x43\x4a\x98\x94\xf0\xa8\x29\xc7\x6f\x29\xe0\xdd\x6b\x5b\x4a\xde\xea\x52\x3a\x50\x4b\x86\x05\xb8\x20\x1c\x37\x9e\x7b\x6c\xd1\x63\xd3\xa9\xc2\xa0\xdd\x41\x8c\x84\xb5\x0b\x07\x3a\x96\xa3\x5e\x50\xcc\xf2\x56\x83\x90\x0f\xd4\x62\xaa\x05\x4f\x17\xcb\x08\x43\xe6\xcf\xe5\x12\x92\xd3\x46\xdb\xa0\x6a\x54\x03\xc1\x1a\x58\x1c\x59\x63\x77\x15\xab\x61\xa5\x0d\x0f\x29\x62\x46\xe6\x6a\xab\x2c\xb9\x88\x97\x36\xf0\x40\x0a\x94\x87\x19\xf9\xc4\xcb\x8a\xc3\x6c\x05\x3d\x40\x36\xf5\x79\x8a\xa5\x90\xd1\x25\x80\x1a\xd9\x84\x53\x05\xcf\xab\xe1\xea\x5b\x4e\x95\x52\xb2\x8a\x75\x47\x38\x03\x49\xb0\x8d\x31\x12\x6a\x8c\xfa\x5a\x2d\xf4\xe1\x12\x2e\x60\x2e\x89\x4a\x92\x5c\x4e\x61\xbf\x43\x10\xde\xd6\x82\xf0\xd5\x2d\x82\xf2\x4e\xbc\x1e\x3e\x7a\x6f\xff\x70\xff\x64\xbf\x89\x20\x7d\x1c\xd7\x22\x9d\x95\x17\x85\x0e\x73\x9e\xc5\xbf\xee\x0b\x30\xe4\x76\x87\x3b\xc0\x4e\x0c\x02\x8e\x63\x75\xd0\xb6\xfb\xab\x4d\xb7\x00\x0e\xaf\xf8\x1a\x4c\x19\x41\x77\x03\x8c\x45\xec\x1c\x89\xb9\x82\x73\xe6\xef\x54\xa0\xf7\x51\xdb\x90\xf6\xae\x5c\x72\x10\x2b\xc7\x9a\xaf\x71\xa7\xd3\xd4\x51\x8c\xd6\xf7\x32\xf4\xe8\xd2\x44\x8c\x31\x60\x37\x66\x02\xfc\x44\xb9\xc4\x7c\x88\x3b\xa3\x05\x6a\xd8\x22\x85\x0b\x2a\x2b\x1c\x87\x96\x48\xde\x4b\x97\x4c\xee\x61\xba\x2c\x95\x7c\x4a\x95\xa7\x51\x4e\xe1\x3c\xb6\x0e\xc9\x3f\xc6\xb0\x09\xa3\x2f\x14\x4e\xba\xac\x45\x2b\x9b\xf8\xe6\xf2\x0a\xbb\x31\x67\xe4\x43\xdc\x7e\xf4\xf0\x4a\xc0\xd7\x18\x21\xcd\x62\x9a\x83\xc6\xa8\x6e\xc7\xa6\x52\x8b\x42\x83\x76\xa8\x85\xc3\x0f\x90\xef\xdf\x28\x3e\xb2\x4b\x76\x63\x90\xb3\x79\x15\xd3\x8e\xd5\xce\x0f\xf0\x78\x41\x29\x63\x43\x6e\xd3\x55\xc4\x1f\xa5\x55\xd8\xcd\xfd\xb3\x78\xb8\xf6\x36\x25\x02\xec\x92\x59\x8c\x47\x01\x5e\x42\xbe\xa6\x94\x82\x5d\xdb\xbf\x45\x7d\xff\x36\xe4\xd6\x5d\xed\xfd\xdb\x7a\x9b\x5e\x62\x05\x35\x33\x36\x70\x05\xa1\xb1\x1f\x83\x3b\xb4\x29\xc8\x25\x76\x11\x2e\x35\x0a\x88\xa6\x11\x16\x68\x1a\x9e\x35\x5d\x41\xd3\x90\x1a\xdf\x17\x4a\x4d\xbe\xca\x61\xc2\x9c\x82\xd7\xe2\x3c\xb0\x82\xfd\x21\xe9\xe1\xed\x2d\x7c\xe3\x34\x5e\x9f\x21\xe7\x30\x5e\xe3\x89\xda\x4d\x3d\x2b\x3c\x7e\x7c\x2b\x8f\xdf\x5e\x9d\x75\x04\x87\x5a\x02\xec\x29\xb3\x43\xd4\x65\x89\x6a\x67\x02\xfe\xda\x4c\x19\x11\x5a\x80\x28\x98\xf0\xdb\x58\xed\x4f\x89\xdc\x9f\x84\xde\x9f\xcc\xc6\x6e\xc2\x5f\x9b\xf8\xd4\x2a\x14\x53\xda\x82\xc5\x21\x7b\x37\x46\xf2\x3d\x42\x3d\x1a\x4e\xe3\x1a\x82\xc7\xba\x27\xaa\x39\x6e\xca\x89\xa9\xc2\xe1\xd8\xbb\x65\x42\xce\xd6\xd9\x58\x7f\xb0\xf7\x66\x00\xec\x44\x32\xa1\x33\x53\x00\xff\xac\x38\xd1\xf7\x58\x3b\xd0\x85\x91\x7b\xe1\x06\x88\x04\x91\x76\x79\xa3\xcd\xb5\x37\xda\xab\xb8\x3b\x13\xb4\x72\xfd\xfb\x26\xdf\xf3\x5e\xbd\xe2\x73\xb7\x01\xff\x85\xd4\x4b\x7c\x6c\x15\x5e\x16\x3d\x61\x8e\x13\x89\x38\xee\xf0\xfc\xfb\x2c\x77\x0b\x78\x2f\x57\xcf\x7a\x47\xbe\x48\x30\x67\xd1\xe6\xc6\x17\x8b\x24\xf1\x96\xbc\xf5\x0a\x47\x3e\xc7\x8d\x19\xf7\x9a\xee\x7f\xbf\xe8\xc9\xf7\x2d\xd6\xee\x8e\x73\x81\x3e\x75\xbb\x36\x99\x32\xf2\x32\xa6\xb5\xc4\xe8\x85\x67\xe2\xfb\x58\xe7\x51\x57\x5f\x58\xe5\x4f\xbf\x14\xe4\x55\x8c\x52\xe5\x9b\x6e\x13\x78\x31\x8a\x6f\xcc\x04\xd8\x5b\x33\x05\x76\x64\x0a\x60\x8f\x4d\x06\x7c\x4f\x8e\xec\x27\x35\xb2\xcf\xe2\xd2\x49\x32\x71\xe5\x7b\x4a\xcf\x3f\x3b\x0c\xa6\xee\x85\x01\xdf\xe3\xc2\xe7\x52\x44\xb1\x1b\x06\x07\xc1\x34\x2c\xfc\x26\x2f\xc2\x8f\xea\x66\x6d\x42\x78\xea\x7a\xce\x9e\xf2\xa7\x6c\xdc\x3b\x8d\x45\x54\xbf\x17\xb1\xc0\xbe\x6c\x64\x98\xcf\xdc\xa5\xb6\xb2\x5a\xeb\x97\x82\xbc\x89\x0b\xb7\x43\xdd\x45\x2f\x8d\x11\x6d\xfc\x5b\x2c\x8b\xcf\x54\x31\x3c\x8f\xef\x96\x99\xa0\x94\x5e\xd4\xf9\x36\xe6\x22\x78\x16\x37\xe5\x85\x48\xca\x0b\xea\xc0\xe1\x5d\xbc\xee\xcc\x56\x03\x2f\xc5\x50\x6a\x33\x7b\x31\xbc\x4d\x6b\x0c\x83\xbf\x37\x7f\x70\xcc\x73\x9c\x6b\x4e\x4b\xe1\x45\xdc\x09\x5c\xcb\x1f\x29\xe4\xda\xed\xd5\x93\xf6\x07\x9a\xc1\x5c\x90\x68\x0a\x07\x92\x2f\xf0\x2d\xdc\xc6\x18\x22\x4c\xa1\x17\xd8\xca\x8e\xb6\x65\x22\x26\x6a\x6a\xda\x60\x9f\x9a\xbb\x29\xc1\x1d\x91\x35\x45\x5e\x1b\x5c\xeb\x82\x9c\xc4\xf0\x15\xb9\xcd\x27\xdd\xaa\x64\x16\x6a\xbf\x7a\xca\xea\xc7\xae\xba\xed\xa2\xd1\xef\xb2\x51\xb0\x3f\xe1\x66\x83\xc3\x77\x9e\x02\x5b\x75\xd6\x2f\x1e\x3b\x35\x3f\x2b\x81\xb7\xd4\x70\xde\xa6\x44\x07\xca\x8b\x06\xba\x95\x32\xd4\xc8\xae\x70\x6b\x97\x1c\xc6\xa0\x31\x86\xa6\xb9\xec\xe6\x67\xd9\x3d\xc4\x57\x7e\xca\xea\xf8\xca\xd5\x7b\x5e\xa5\x64\x4a\xc1\xfe\x8c\xea\x33\xf6\xec\xa4\xd6\xb3\x27\x5a\x81\x5a\x65\xbf\xf6\xa9\x79\x96\x12\x8f\x16\xbd\xc4\x89\x3d\x95\x82\x93\xed\x2a\x45\xfa\x50\x10\xaf\xa6\xb2\x96\xe8\x70\xab\x0d\xed\xa5\x24\xa3\xcd\xcf\xfd\x90\x92\x23\x79\x97\xb6\x41\x7f\x15\xcf\x1d\x36\x75\x93\xcd\x76\xa8\xaf\xa0\x12\x02\xc7\x5b\xf5\x2a\xef\x53\x52\x2f\xdb\x6e\x7f\x3c\xa9\xe1\xe3\x2d\xa7\x28\xe9\xcd\xc8\x3b\xad\x2f\x35\x36\x55\x47\x11\xa0\x92\x68\xf8\x96\x6c\x28\x55\xc0\xe3\xcc\x72\xda\x08\x10\x8f\xb3\x4b\x92\xdb\xd2\x38\x6d\x48\x6f\xaa\x11\xfb\x93\x6a\x44\xd2\xdb\x53\x66\xf5\x57\xa7\xf2\x93\x19\x5a\xfd\x0a\x87\xab\x41\x5f\xd8\x9e\xaf\xe8\x43\xb7\xf7\x59\x35\xe4\xaf\x36\xf4\xd9\x8c\xa5\xda\xdf\x46\x0e\x9b\x1a\xf7\xec\x80\xdc\x94\x0d\x9d\x17\x7d\xba\x5c\x6d\xea\xdc\xbc\x6c\x7c\xd8\xf8\xc1\xb2\x50\xf2\x64\x45\xb0\x59\x99\xe7\x6c\xa5\xca\xa3\xe5\x2a\xde\x4a\x95\x65\xc4\x31\xdb\xad\x55\x69\x17\xf5\xec\xb0\x29\xea\x7d\x8c\xd7\xe6\x37\xfa\x71\x6d\x0a\x58\x98\x09\xa4\xca\x77\x34\x85\xef\x6a\xe3\xf8\x14\x77\xe0\x3f\xfe\xf6\x1b\xd1\xce\xa3\x4c\x19\x89\x79\x91\x12\x74\xc8\xe0\x53\x8c\xb6\x23\x6a\x9e\xe4\xf0\xba\x93\x9f\x5e\x27\xc5\x29\xf4\x44\xa5\x43\x31\x8b\x9c\xa2\x85\x33\x80\xd7\x78\x79\x12\x2d\x6a\x8f\x3a\xc2\x0e\x1d\x71\xfa\xe1\x60\x37\xf4\xe7\x61\x20\x02\x84\xeb\xc8\x6d\xa6\x25\x80\x2a\xc9\x68\x0e\x91\xd7\xb9\x55\xcc\x12\x30\x2c\x03\x02\xed\x9a\xcc\x7f\xfb\x2d\x51\x88\xef\xf7\x92\x3a\xdc\xbb\xf6\x8c\x81\xd4\x0a\x3c\xe5\xbe\xbd\xea\x90\x1d\x55\x46\x46\xc9\x50\x3d\x22\x1a\x26\x54\x1b\x5d\x7e\x30\x33\x0c\x83\xd7\x31\xb1\x87\x0c\xdd\x42\x6a\x19\xa1\x13\xaf\x2b\x62\xf3\x69\x4b\x3a\xff\x46\xce\x80\xa0\xe8\x69\xe1\x0b\x14\x0d\x53\xfd\x49\x1a\x3c\x1a\x93\x72\x31\xe5\x78\xad\x52\x16\xb4\x26\x2b\xb8\x4e\xd4\x41\x59\xd7\x6f\x39\xa0\x24\x20\x17\xe4\x63\x0c\x27\x40\x84\x1e\xc3\xfb\x52\xcb\x67\x89\xa4\x18\x29\x43\xff\xf6\x1b\x86\xb0\x88\x21\x9b\x88\x21\x37\x05\xa5\x20\xc7\x80\x60\x9a\xf9\xf7\x74\xd8\x9f\x38\xa9\x89\xe0\x6a\x91\x07\x4e\xaa\xd3\xb3\xfc\x66\x28\x47\x10\xd9\xd4\x03\x98\xab\xbc\x0e\x20\xbc\x35\xb9\x06\x0b\x09\xe8\xc2\x4c\xe0\xab\x24\xde\x1b\x53\xc0\x07\xd3\x86\x63\x93\xc1\x89\x99\xc2\x4b\x45\xc8\xa9\xd7\x4c\x81\x53\x05\x16\xb5\x25\x21\x22\x65\x2e\x97\xa9\xab\x22\x90\x71\x15\x31\xaf\xdb\x90\xf2\x31\x86\x68\xf8\x1d\xa2\xa1\x64\xb5\x0b\x88\x86\xd7\xa0\x8f\x1c\xd1\x11\xac\xf1\x24\x83\xa0\x70\x5f\x08\xda\x66\xb6\x98\xc7\xef\x78\x46\x90\xe2\x11\xc1\x02\x4f\x08\xae\x1b\x99\x61\x99\xa7\xd0\xdd\xc0\x56\xf3\x51\x49\x86\xaa\xbf\xae\xd7\x81\x24\x12\x1e\x86\xd7\x22\xda\x65\xb1\x20\x34\x87\xd0\x6b\xf7\x2e\x4c\x3d\x0c\x3f\x7c\x99\xc2\x8e\x0b\x7b\x36\x51\x90\xa1\x1e\x44\x36\x31\xa6\xcc\x8b\x85\xa1\x8e\x65\x60\xda\xb5\xbe\x02\x29\xdc\x3c\xed\x1e\x68\x04\x47\x15\xa0\x96\x6e\x4e\x81\x7b\xdd\xc0\x1f\x53\xd9\x1b\x49\x40\xad\x27\xe6\x8b\x5a\x6a\x07\x1c\x0b\x39\x7a\x72\xec\x22\x08\x86\xd7\x40\xf0\x8c\xfe\x9c\x12\x74\x40\xa3\x5f\xd0\xd9\xa9\x38\xf8\x8d\x6b\xdf\x1f\xb6\xd2\xc5\x9a\x09\xc1\x13\x1b\x7e\x5e\xae\x35\x35\xad\x09\x7a\xa5\xd4\xd0\xc3\xe7\xc4\x86\x90\x4e\x8a\xde\x21\xa7\xb3\x21\xa2\x98\x3a\x55\xce\xd8\x17\xc9\x2d\xcb\xf4\x0d\x39\x78\xeb\x26\xa5\x8b\x27\xdf\x43\x4e\x3c\xd1\x7e\x92\xe8\x0f\x99\x43\xe6\x59\x33\x62\x7b\x20\x3c\x98\x11\x7e\xdb\x3f\xb1\x47\x8a\x64\x5e\x14\x3c\xaf\x96\x6a\x18\x7f\xa9\x9c\x3e\x78\x60\x97\x7a\xb0\x92\xd5\xa7\xa0\x96\xc8\x26\x0b\x95\x47\x58\x3e\x54\x26\x07\xa2\x14\x42\xaf\x96\xa2\x48\xff\xae\xf2\x11\xe9\x1b\x3a\xce\x0a\x73\xe8\x7b\xcb\xbe\x2c\xfc\x2f\x9e\x22\x08\x2d\x4e\x6c\xe4\xe8\xe1\x72\x36\xe6\xa9\x15\x56\x42\x5e\xe7\xe4\x91\x29\x92\x54\x35\x7b\x14\x8c\xe3\x93\x0f\x07\x6f\x5f\x18\x70\x9d\x50\xe8\xcb\x6f\x98\xaa\xb1\xad\xac\x47\x80\xf7\x1c\x75\x5b\x38\xae\xf2\x91\xf0\xbd\xba\x66\x1d\x61\x76\x43\xbd\x05\x05\x90\x5a\xc9\xda\xd5\x14\x01\xa6\x86\x48\x8b\xf5\x74\xe9\xad\x81\x32\x2a\x4e\x31\x22\x0a\x7c\x66\xee\xca\x99\xf3\x43\xb2\xef\x52\x98\xb9\xe4\x04\x7d\x59\x72\x0a\x17\x5d\x7d\xd7\xb4\x12\x88\x6b\x43\x6a\x6a\xbe\x07\x97\x5e\x83\x60\xf0\x47\x11\xa3\x86\xb4\x30\xd7\x94\xd8\xd2\x77\x4e\x84\x24\xec\x45\x02\xf7\xc6\xf2\xdf\xe2\x7f\xcc\x95\xce\x57\x5e\xdf\x20\x4c\x0a\xd7\xed\x9d\x74\x3c\x0a\x0b\xcf\xc2\xbb\x4a\x0b\xa4\x70\xe3\x59\x44\xa4\x16\x1a\xd4\x6c\x0f\xbe\xa7\x30\xf7\x50\x5a\xf7\xe0\x73\x0a\x8b\xe2\xfa\x2c\x85\x8b\xe2\xfa\x55\x0a\xd7\xc5\xf5\x5e\x0a\xfd\xe2\x7a\x37\x85\xac\xb8\x56\x68\xf4\x2d\x1f\xa6\x44\x9b\x9c\x7e\xa1\x6d\x1e\x39\xc8\x00\xdb\x56\x33\xba\x5b\x09\xd4\x1e\xf7\x3d\x2b\x49\xe0\xca\x6b\xc5\xbf\xd0\xdb\xd4\x9e\x0d\x33\xb2\xef\x21\x4a\x40\x05\x22\xff\xcf\x7f\x4e\x70\x78\x82\x21\x7b\x40\x15\x3c\x06\x9f\xa8\xf4\x2b\x51\xc1\x28\x94\xb6\x8c\x36\x7a\x8a\x39\xb8\xcc\x23\x22\x77\xf3\x45\xa2\xf4\xe5\xc4\x83\x1b\x0f\xbe\x92\x00\x7e\xb0\x07\x68\x2e\x4d\x30\x31\x81\xfd\xde\x4c\x86\x3c\x6f\xe6\xe3\x3c\xc4\x7c\x08\x39\xec\x78\xd6\x8f\xbe\xf9\x30\x87\x63\xbc\x18\x8f\x73\x98\xa9\xab\xed\x1c\x76\xdb\xbe\xe4\xca\x23\x41\xe9\x6d\x5e\x99\xc0\x0b\xe5\x44\x3e\x3a\xd2\x6e\x9c\x4d\xff\x09\x8d\x1e\x5b\x15\x6c\x9a\x0d\x7c\xd7\xaa\x60\xcb\x6c\x00\xc3\x56\x05\xa3\xaa\xe0\x41\xa3\xa0\x14\xdf\x8f\xbd\x25\x3f\x8b\x99\xb7\x92\x14\xcb\xcb\x73\x38\xf0\xee\x92\xb3\xfe\xc8\xeb\xce\x86\xa5\x22\x73\x21\x84\xa9\x1c\x12\xb9\x34\xad\x19\x39\xf0\x94\x1f\x22\x97\x82\x52\x9c\x82\x31\x8f\x42\x27\xc5\xc7\x0d\x98\xa6\x88\xcd\x2d\x35\xe3\x89\x14\xc1\x4c\x39\x7b\x5e\xdb\x53\x17\x4b\x39\xfb\x8a\x27\xb3\x96\x30\xb6\x69\xcd\xe5\xa9\xa9\x26\x4e\x57\x32\x55\xf6\x8e\x53\x0c\x4b\x73\xd4\x4b\x31\xcd\x7e\xf9\x52\x67\x29\x44\x73\xa6\x5f\xda\xb7\x76\x52\x52\xf4\xf8\x32\x49\xe6\xe6\xfd\xfb\x5e\x68\x33\xef\x32\x8c\x13\xf3\xc9\xe8\xc9\xd6\x7d\xa3\x66\xa4\x79\x11\xc3\x2e\x8e\x07\x09\xad\x04\x5c\xeb\x87\x3a\x15\x3e\xc1\xa3\xd4\xb0\x3a\x37\xf0\x52\xe0\x27\xe6\x38\x07\x66\x35\x0e\x91\xed\x7d\x33\x01\x34\xb3\x02\x7f\x8d\x87\xd6\xb6\x95\x40\x6a\xb5\x9c\x34\x9f\xd4\x4e\x95\x17\xf8\xa4\x5d\x1c\x74\x4b\xf5\x76\x46\x2e\xa5\xea\xea\x51\xe0\xdb\x66\x1f\xf8\x23\x39\xab\x09\xf0\x27\x66\x98\x82\xed\x9a\x0e\xd8\x9e\x29\xac\x10\xf1\x95\x3d\xb0\x53\x33\x03\x3b\x33\x85\xea\x82\xfd\xdc\x8c\xc1\x3e\x35\xa7\x60\x4b\x35\xcb\xfe\x64\xba\x60\x7f\x36\x19\xf0\xf7\xe6\x4d\x9a\xab\xa8\x58\xcf\xfa\x1c\xc8\x6e\x7c\xe8\x24\xa7\x22\xf7\x69\x64\x46\x88\x9b\xb8\x53\x44\x46\xc0\xb9\xd7\x1d\x43\x5f\xa8\x5b\x89\x79\x4e\x12\x38\x27\x95\xaa\x75\xb2\x46\xf0\x0a\xe5\x26\xe4\x14\xa0\xac\x6f\x3d\xeb\x44\xf2\x75\x8f\xc5\xf1\x5b\xe6\x0b\x83\xc2\xa9\x57\xc4\x8a\xf2\x99\x54\xf9\x0e\x3d\x2b\x88\x88\xe1\xb8\x99\x41\x61\x4f\xfd\x88\xe7\x2c\x30\x28\x9c\x79\xd6\xeb\x00\xbe\x4b\xf2\x3c\xf4\xe0\x04\x90\x0d\xef\xe9\xab\x33\x8f\x18\x87\x21\x73\xdc\xe0\x62\x38\x1c\x1a\xf4\x8b\x02\x0c\x7c\xe5\x59\x49\x04\x9f\xbd\x0e\x10\xe8\xc2\xf8\xfd\xb2\xa3\xc2\x23\x5d\xfe\xbe\xa3\xfc\xa1\x2e\xff\xd6\x2a\x70\x1d\x13\x29\x2e\x9f\xce\xe7\x85\xb8\x4c\x73\x78\xd3\xc6\xc0\x5e\x25\x3a\x9f\xf7\x92\x67\x75\xd0\xc8\x9a\x9d\xd4\xd3\x82\xbd\xb1\xe1\x9b\xd2\x26\x41\xd0\x1c\x9e\x75\x48\x7c\x87\x9e\x1c\x9c\xb7\x85\x5c\xd6\xc3\x7f\x07\xd7\x2c\x0a\xa4\xc8\x25\x37\x16\x35\x76\x6f\x24\x0b\x55\x70\xcd\xcf\xbd\x5f\x38\x5d\x54\x47\x8b\x85\x75\xa5\x79\xca\xf6\x7d\x85\xcf\x3d\xf3\xca\xf3\xc4\x77\x6a\x6a\x79\x9a\x24\xa1\x9c\xdc\x17\xde\x1d\x91\x55\x3f\xb6\x7e\xe9\xeb\x94\x04\x8c\xcc\xc8\x0b\xe4\x5b\x0a\xb2\x91\xc1\x91\x39\xd2\xd8\x8c\x39\xea\x1a\x9f\xd4\x4b\x5d\x83\xc2\x6b\xcf\xb2\x23\x08\xb2\x6e\xd2\x7d\x2d\x65\x0a\xfd\xf6\x48\x65\x99\xc8\xda\x07\x39\xc8\xc0\xb0\x3d\xd7\xbe\x32\xe0\x52\xa8\x23\xde\x24\xb3\xdc\x08\x44\xd6\xa5\xdb\x4c\x8c\x29\x1b\xf8\x6e\x90\xc6\x86\x29\x2f\xe7\x5e\x1a\x1b\xd5\xec\xbe\xc3\x69\x8b\x32\xc9\xb4\xe4\xe4\xf1\x24\xe8\xf1\x24\x18\x84\x69\xe2\xb9\x81\x18\xb8\xc1\x34\xec\xf1\x30\x72\x44\x34\x18\xf5\xfc\x68\x30\xee\xf9\x7c\x30\x46\xd9\x2a\xc9\xc0\xf0\x59\x74\xe1\x06\x03\x4f\x4c\x13\x03\x8c\xc1\x56\x24\xfc\x62\xb2\x67\xe4\x53\x49\x13\x53\xd6\x33\x36\x12\x59\x70\xa2\xdd\x73\xd3\x0c\x57\x68\xe2\x26\x9e\x5c\x9d\x2c\xc3\x01\x4b\x3d\x83\x82\xad\xae\x99\x41\xc1\xed\x18\x88\x13\x0f\x8c\xcb\x48\x4c\x0d\xb8\xff\x5f\x33\x96\xb1\xd8\x8e\xdc\x79\x62\xde\x77\x87\x89\x88\x31\x90\x2b\xa0\xc3\x48\xcc\x3d\x66\x0b\x72\xff\x9f\xf1\xfd\x0b\x30\x0c\x4a\x31\x75\xa6\x76\x08\xcc\x21\xcc\x94\x63\x70\xe7\xc4\x9c\x88\x02\x52\xbd\x5b\xdf\x0b\x75\x15\x72\x48\xfe\x51\xec\x10\x06\xe0\x55\x2c\x2f\xbf\x48\xd1\x66\x9a\xad\x4f\xd3\x28\x35\xa2\xa6\x81\xa6\x86\x5e\x89\x22\x7f\x46\x12\x5a\xa5\x5b\x2c\x17\x30\xab\x82\x9c\x22\xf4\x6f\x54\x18\x97\x81\x25\x20\x52\xc9\x17\x2f\xf1\x54\x1f\x2f\xb3\x84\xa4\x88\x6f\xa9\xcc\x8b\x95\x51\xa5\xb3\x3a\x56\x8e\x6e\xa9\x1c\xa9\x44\x65\xbd\xf6\xce\xad\x74\x28\x4b\x08\xd1\xbd\x55\x49\xa9\x13\x65\xad\x6c\x7d\x83\xea\xc3\x46\xed\x2d\xcd\x42\x55\x20\x75\xf2\x56\x42\x39\x24\x05\x20\xe9\x30\x9e\x7b\x6e\x22\x49\x61\xe3\xfe\x85\x5c\x37\xb1\xa6\x3f\x16\x5d\x88\x44\xca\xea\x1d\x94\xb6\xe4\xfb\xde\xf4\x35\x3e\xf3\x94\x7b\x71\x8b\x47\xbc\x9d\x49\xda\x77\x71\x61\xc5\x19\x31\xbe\x72\x8f\x05\x57\x35\x46\x18\x29\x26\x88\xf9\x7a\xa6\x19\xf0\x4c\xea\x44\x27\xc8\x3d\x32\xb5\x00\x12\x47\x6a\x07\xfa\xfa\xd2\xa0\xd0\xd7\xd7\x52\x6d\xf1\xb3\x56\x8f\x4d\xed\xe1\x5a\xf5\xa3\x9f\x15\x1b\x98\x93\x15\xab\x31\x11\x37\xc9\x20\x08\xaf\x23\x36\xaf\x77\x48\xee\xd1\x1a\xfc\x36\x2b\xeb\x5e\x0f\xc6\xa3\x11\xd6\xf2\x90\x06\xb1\xd3\x97\x59\xb7\x87\x4a\x80\xf1\x73\x43\x36\xa2\x74\x52\xe3\x2f\x52\x52\xbf\x9d\xc1\x14\x2a\x75\x2b\x07\x29\x18\x99\x64\x43\x9b\x86\x62\x26\x20\xb7\x63\x3c\x06\x94\x3d\x33\x8b\x17\xde\xfa\x26\x49\xd7\x19\x29\x7b\xda\xf5\x3e\xc9\x2d\xbb\x5f\x27\x15\xcf\x0e\xb2\xb1\xb3\xbb\x76\xc3\x95\x13\xdf\xf5\x7e\x7c\xc2\xbe\x64\x51\xb2\xd2\x8b\xe3\x30\x8d\x6c\xa1\xfa\x01\xf3\x3b\x52\xc3\x61\x7d\x74\x06\x28\x6a\x63\xc3\x92\xa9\x6f\x56\xc3\xbe\xb7\x32\x88\xb1\x5f\xf4\x39\x72\x2f\x2e\x93\xc1\xa8\x87\x44\xe4\xa7\x68\x0f\xd1\x9b\x41\x1a\x8b\x68\x10\x0b\x4f\xd8\x72\x33\x70\x03\x37\x71\x99\x57\x96\x0e\xfc\xf0\xfb\xe0\x96\x2a\xd7\x82\x5f\xb9\xc9\x2d\xb5\x74\x47\xec\xd0\x93\xa2\xba\xf1\x37\xdb\xb6\x1b\x64\xfc\x77\xcb\xf8\xfb\x46\xb2\xf1\x77\xe3\xef\x9a\x9a\xdf\xb5\x7e\xce\xc5\x60\xca\x1c\xe1\x34\x26\x27\x16\x76\x18\x38\x2c\x5a\x28\xfa\xf8\xe8\x11\x95\x48\x96\xca\x0d\x8b\x18\xcf\x51\x99\xef\xf1\x45\x2f\xb9\x74\xe3\x9e\xc7\xb8\xf0\x6a\xaf\x36\x36\x0a\x71\x30\x87\x6b\xb5\x56\x3d\x29\x02\x2c\x1a\xcb\x25\x85\x72\x86\xee\x98\x28\x34\x25\x01\x9d\x1c\x11\x7d\xf0\x20\x55\x5e\xa9\xff\x26\xa0\x6f\x88\x7a\x62\x61\x65\xae\x86\x23\x72\x02\xca\x3a\x42\xe1\xa6\x8d\x46\xeb\xae\x1b\x81\xb8\x9e\x28\x3b\x85\x65\x6c\x9c\xd9\x45\xbe\x2b\xd8\x6f\xa3\xaa\x1d\x97\x04\xe8\x84\xf6\x06\x05\xc9\x46\x78\xde\x2f\x51\x3d\x41\xda\xbc\x84\x9b\x6c\x35\xc4\xa8\xfc\x98\xcf\x2a\x75\xf8\x48\x27\x0f\x77\x31\x0f\x26\xed\x5e\xb0\x5c\x78\xde\x20\xf6\x58\x7c\x39\x08\x57\x97\x8c\x76\xf5\x43\x4f\xbc\x2a\xb9\xf9\x0a\xd7\x6e\xfb\x00\x87\x05\x17\x72\xea\x1b\x9f\xd0\xf4\x7f\x11\x77\xe8\x55\x57\x9f\x1c\xbd\x90\xaf\xb2\x75\x89\xf5\x07\x9b\x5d\x62\xbb\xf3\x34\xb0\x66\xe4\x2a\x53\x41\x97\x43\x41\x8b\xac\xfa\x3b\x1d\x0c\xea\x2a\x03\x85\xe3\x7c\xac\x37\x15\xc6\x51\x10\x9b\x65\xd6\xc9\x14\x76\x3b\x9e\xda\xab\x49\xf9\xee\x45\x20\xd7\xe8\x74\x60\x8b\x40\xae\x8a\xf2\xcb\xd4\x62\x98\x65\x92\x4e\x8e\xf4\x72\x38\xc8\xd6\x5b\x13\xac\x73\x82\xa7\x34\x8b\x4c\x7b\xb6\x0b\x88\x04\xa9\x65\xd4\xa6\xf5\xac\x8d\x9d\xe2\x18\x2f\xc5\xb1\x80\x62\xea\x46\x49\x30\x43\x7e\x29\x49\x06\xc3\x51\x78\x4d\x5b\xbf\xce\xd4\x6c\x49\x9e\x32\x0f\x63\x57\x59\x2a\xd0\x08\xe7\xda\x86\xda\xae\xd4\x67\xba\x89\xf0\xe3\x01\x42\x52\xf5\x3c\x37\x4e\x14\xe7\xc4\xdb\xd5\xde\x35\x97\x02\x32\x1f\x6c\x57\x6c\xb4\xe2\xb6\xb8\x8b\x22\x93\xed\x39\x83\xa9\x27\x6e\x7a\x2b\x0d\x17\x8f\xed\xca\x6d\x16\x46\x7f\xec\x64\x52\xe9\x7a\x25\x37\xd1\x57\xad\xc6\xc8\xd7\xe8\x9f\xa0\xb2\x03\xa1\x01\xf2\x32\x53\x51\x28\xa6\xa4\x2b\x83\x02\xc1\x0c\x7c\x0f\x81\x0d\xfb\x13\x75\xcb\xbc\xc8\x10\x6d\x89\xc2\x3e\xbe\x85\xa4\x56\x02\x3b\x2e\x49\x71\x41\x3b\xb4\xaa\x78\xe7\xb5\xac\xf6\x01\x57\x6f\x89\xed\xe4\x2f\x16\xa2\x83\xfa\x0f\x2a\x9b\xfa\x17\x8d\xbc\x3f\x27\x11\xe2\xe4\x15\x12\xc4\x71\x25\xb6\x48\x12\xed\x95\x43\x39\xc6\x86\x90\x75\xf8\x99\x9a\x68\xf6\x8a\x56\x9f\xaf\x95\x77\xac\x30\xcf\xc0\x2e\x02\x03\x8f\xb2\x5b\x82\x75\x93\x21\x9f\x74\x07\x3d\xde\x71\x4b\x1d\x57\x5d\x6c\xd9\x52\xff\x73\x36\xcf\x07\xdc\x1e\x39\xe2\x57\xf7\xcf\x3a\x29\xfc\xcb\x5b\x65\x42\xcd\x2e\xa9\xa3\xd8\x8e\x57\x47\x54\xb6\xf1\x36\x4c\x7a\x38\xe0\x9a\x7e\xbe\x50\x70\x2d\xf6\xf3\x27\x66\x2f\x4b\x21\xa2\x10\x5a\xeb\x57\xcf\x93\x6a\xf5\x88\x0c\x5c\xcc\xbd\x3f\xb5\x8e\x12\x22\x28\x70\xcc\xd1\x30\x9d\xec\x24\x64\x2a\x35\x15\xe4\x45\x86\xd9\xf8\x19\x1b\x10\x5b\x4b\x9d\xf7\x3d\xd5\xd5\x51\x39\xe6\xd7\x97\x6e\x22\x06\xf1\x9c\xd9\xc2\x00\x63\x45\xf0\xe6\xaa\xef\x0d\x92\x3a\x59\xe6\x20\x3e\x1f\x6c\x69\x82\x4f\x13\x08\xe1\x9c\xd8\x80\x2e\x86\xee\x64\x46\x58\xb9\x46\x2a\xee\xa4\xbb\x50\x2c\x91\x19\x39\xc8\x20\x81\x40\x0a\x0f\xc5\x12\x51\xeb\xe1\x6b\xd6\x7d\x5e\x7c\x61\x03\x62\x0c\x40\x96\x42\x86\x76\xfe\x0f\x59\xdd\x7b\x53\xad\x9c\xa0\x3a\xdc\x57\x7f\x2b\x6d\xb6\xfe\x09\x73\x6f\xf0\x40\x77\xe8\xa4\x33\xc9\x98\x47\x8e\x32\x5c\x90\x2e\x1e\xe9\x5f\xe2\x31\xfb\x01\x04\x80\x6f\x0f\x68\x23\x9c\xef\x00\x98\xe5\xa2\x51\x51\xd6\x7c\xda\x6c\x62\x46\xbe\x66\x08\xd0\x0a\x0c\x22\x18\xc9\x06\x2a\xeb\x90\xf1\x36\x54\x33\xa8\x08\x28\xee\x4d\xc3\x34\x70\x30\x10\xeb\x3c\xbb\xc5\xca\x18\x87\xda\xca\x78\x92\x59\xe7\x19\x31\xec\x4b\x61\x5f\xe1\x4a\x7e\xab\xf6\x52\x37\x98\xa7\x52\xa7\x3c\xd5\x32\xa0\xa2\x7d\x38\xcc\xaa\x68\x05\xad\x77\x42\xf9\x30\x9e\xbc\x50\xd8\x5b\x67\xf9\xb9\x94\x32\x88\x01\x33\xd2\x17\x10\xc0\x61\x26\x17\xcf\x99\xd6\x63\x17\x73\xb9\x7b\x7f\xcf\xba\xed\xaa\xc5\x86\x27\xa7\x22\x60\x19\xee\x3d\x15\x7f\x3a\x2d\xcb\xfc\x44\xd2\xaf\x24\x62\x75\x6e\x3a\x90\xaa\x79\x14\x7a\xe5\x4f\xd9\x63\x1e\xde\x54\xcf\xbe\xc5\x67\xcf\x8a\xa1\xc0\x32\xdc\x3d\x9b\x0d\x0c\x8a\x71\x39\xc9\x94\xeb\xc2\x3d\xcc\xc3\x0f\x7b\x99\x3a\xb4\x4f\xe0\x75\x4a\xf5\xe6\x50\x5f\x50\x2b\xad\x38\xae\x8d\x66\xfa\xdb\xeb\x3a\x42\x59\x86\xe4\xce\x5e\x2d\xb8\x40\xb3\x1e\x45\xff\xaf\xb2\xf5\x98\x0f\xdd\xa3\xa6\x73\x8e\xd7\xdf\x2f\xab\x78\x6e\x70\x55\xd7\x64\x45\xa5\x97\x6a\x1e\xcc\xec\x2b\x49\x76\x81\x63\x80\x91\x44\x2c\x88\xe7\x2c\xc2\xf3\x47\xcd\x30\xa6\x61\xa0\x78\xf7\xa5\x88\xdc\xea\xb6\x9d\x46\x31\x72\xed\x79\xe8\x06\xea\xf4\x52\x15\x68\x76\x8c\xcc\x25\x10\x7a\xf0\x8b\xae\x28\xfe\x9c\x28\xb3\x2b\x08\xfd\xd5\x9f\xb3\x3b\x26\x07\x7a\x99\xad\xf7\xbf\x7f\x9f\xad\x4f\xbb\xf8\x2d\xbb\x0b\x4a\x61\x13\x27\xf0\x5e\xf2\xf3\xa7\x14\x75\x13\x44\x0b\xc4\xab\x9f\x3f\x31\xbb\x73\x03\x38\xf0\x8d\x5a\x7f\xa5\x33\x34\x85\x67\x99\xf5\x77\x11\x64\x56\xfd\xec\xe9\xef\xf0\x5c\xad\x11\x57\xd6\x78\x97\x59\x8f\xe1\x45\x66\x8d\xb7\xe0\xa3\x5c\x8f\x07\x3a\x3f\xf5\x75\x02\x5e\x82\xb0\x3e\xf0\xa9\x75\x0d\xb6\xa9\x29\x77\x4c\xec\x53\xe8\x31\xdc\x87\xae\xc4\x3e\xe8\xf7\xa1\xb3\x29\xbe\x6e\x7d\xff\x11\x09\xe0\xde\x48\xd6\x71\x6e\x37\x25\x8f\x2b\x53\xb2\xd3\xc2\x74\x14\x64\xad\x0e\x95\x4a\x9c\x0e\x96\xe3\x80\xe6\x64\x8a\xe3\xbc\xce\x0a\xce\x13\x39\x68\xa6\x12\xb2\xe9\x38\x05\xe3\x4a\x2c\x76\x43\x47\x18\x80\x99\x30\x29\xa4\x4e\x37\x13\xbb\x12\x0b\x27\xbc\x0e\x4a\x2e\x26\x1c\xd9\x14\x5b\xff\x44\x3a\x5f\xaa\x6f\x3b\x05\x5c\xc5\xe7\x12\x5b\xe2\xda\xad\xe3\x4b\x64\x6e\x85\x00\xe1\x3a\x25\x02\x84\xed\x50\xb8\x71\x29\x84\x8e\x3a\xf0\xf1\x99\x27\x59\xf3\xd4\x41\x0a\x51\xe3\x42\x81\x3b\xb7\x1d\x72\xd8\x92\x1f\x86\xde\x80\xa5\x49\xd8\x26\xf0\xaf\x35\xaf\xdc\x45\x9e\x9a\x91\xcf\x19\xdc\x93\x2a\x5a\xc5\xb7\x76\x5d\x7d\x76\xb2\x56\x26\x53\x9a\x6a\xbd\x95\x71\xa3\x15\xe3\xff\xfd\xbf\x8c\x1a\x03\x84\xd8\xe9\xcc\x46\x69\x9f\x29\x43\xc4\x4c\x81\x5e\xba\x68\x5e\x66\xaf\xc1\xb6\x5c\x87\xa4\x52\xda\x8a\x34\x2b\x9f\x87\xea\x7c\xff\x85\x87\x38\xb5\xb6\x94\x4c\x42\xeb\x63\x26\x05\xa9\xa9\x35\x27\x36\xae\x2c\xae\x12\x47\x7f\xcb\x94\x93\x34\x7a\xdf\xa5\x13\xc3\x30\xed\x61\x7f\x62\x5c\xb2\xb8\xe8\xbc\x89\x3f\xe2\xd4\xb6\x45\x5c\x3f\xae\xa8\x06\x38\x0a\xaf\x7b\x41\x38\xb8\x48\x93\x04\x01\x3d\x5b\xd5\xa9\x73\xb5\x64\xb9\x23\xdf\xb7\x34\x43\x72\x06\x8d\x8d\xb8\x3c\xc8\x70\x83\xc1\xb5\xeb\x24\x97\x06\x24\x13\x63\x6b\x34\x9a\xdf\x18\xa6\xb1\x89\x7f\x5b\xe6\xb7\xf5\xf5\x72\xd7\x11\x41\x32\x88\x93\x48\x24\xf6\x65\xdb\x73\xf2\xad\xb8\xa8\x06\xda\x47\xa9\xb9\x87\x3e\xcf\x0a\x8f\x91\x01\x67\xd1\xa0\x04\x34\x45\x86\x3e\x0d\xa3\x72\x67\x43\x9a\x95\x53\x90\x3a\x64\xc9\x3e\x2d\x77\xa5\x17\x59\x0d\x20\xa8\x75\x7a\x9e\xea\x9a\xef\x32\xaa\x5d\x2f\xe5\x5c\x14\x2c\xed\x88\xb0\x5a\x82\xea\x68\xc8\x7e\xfe\x8c\x86\x7c\xd8\x9f\xcc\x43\xb3\xa0\x4c\x79\x83\x95\x32\xd5\xcb\x4c\xb6\x5c\xfc\x9a\x87\x39\x05\xe6\x90\x56\xd0\x2f\x7c\xe9\x44\x3e\x30\xa6\x26\xd6\x4c\x1c\xf2\x3e\x6b\xd9\xcd\x6b\x23\x35\xe0\x49\xb0\x6e\x05\xcd\x23\xd7\x57\x76\xbb\x37\x19\x99\x52\x70\x5b\x54\x0d\xb9\x72\x92\x49\xd7\x32\xee\x2d\xbd\x4d\xca\x40\x9b\x6d\x73\xd8\x3a\x7f\xeb\xd5\x65\x65\x2e\xfa\x94\x11\xfe\x17\x98\xae\xd4\xff\x95\x0c\x0f\x33\x12\x3a\x65\x5b\x92\x48\xa4\x7a\xd9\xd0\x31\xab\xc1\xd8\x45\x01\xa9\x80\xca\x85\x9e\x18\x5e\x0c\x8d\x76\x86\x82\x72\x8c\xb6\x96\x2a\x02\xe7\x2c\x16\x28\x68\x20\x73\x79\x9f\x91\x67\x59\x8d\xb1\x3c\xcb\xaa\xde\x7d\x51\x5e\xb1\x9e\xb3\xfe\xb8\x3b\xeb\x28\x7f\xa0\xcb\x1d\xe7\x8e\x87\xb5\xfd\x2e\x26\x56\x1c\x48\x50\x3a\x29\x81\xd1\x8d\x95\x03\x50\xf9\xd9\x4e\x14\xce\xe5\xd6\xa4\xcc\x3a\xea\xd0\x49\x72\x37\xc7\x41\x6a\xa7\xcb\x47\x37\x14\xfc\x35\xbb\x96\x1f\xa6\xb1\x40\xc3\x58\x75\x56\x7b\x79\x5b\x7d\x4f\xb0\x4c\x54\xf5\x2f\x9c\x75\xd2\x7c\x25\xb1\x4f\x1f\xf6\x1c\x97\xf7\x7c\xbe\xd9\xf3\xa3\x56\x0b\x93\x32\xd1\xdd\x22\xb1\x9f\xe0\x61\xd5\x5e\x46\x92\x96\xa5\x38\xf7\x1a\xd6\x3d\x03\x43\xc9\x4a\x19\x7a\xee\xac\x77\x5b\xb8\x76\xee\x28\x6d\x2e\x9c\xf5\x51\xe4\x37\xce\x7a\x69\x73\xdf\x59\x2f\xad\x5e\x39\xd6\x63\xd8\x71\xac\xed\x11\x1c\x3b\x52\x08\x9c\x39\xd6\xd6\x63\xd8\x75\xd6\x99\x5d\xef\x45\x95\x42\xbb\x48\x4a\x9b\x2b\x57\x3c\x34\x1a\x22\xd6\x59\xe1\x61\xe5\x92\x84\xea\x8c\x52\x68\x80\x3d\x58\x33\xe9\xdc\x4b\x6b\xe4\x71\xd4\xe8\x44\x52\x1e\x13\xa0\x88\xcc\x3e\xa3\x9b\x28\xbf\x52\x7e\xa2\x1e\x46\x43\xd9\x09\xb8\xb2\xec\x35\x1a\x3a\x66\x2e\x7c\xcc\x08\x02\x19\xec\xd9\xdd\x36\xd2\x5d\xa7\xb0\x91\x7e\x47\x64\x4b\xc4\x0d\x99\x5a\xc9\xe4\x46\xf2\x76\x45\xed\x42\xed\xd5\x33\x17\xad\x83\x77\x6f\x31\x55\x67\xcb\x2d\xfb\xf5\x2d\x9b\x9e\xe6\xba\x8b\xc1\xd4\x15\x9e\xd3\xb9\xe1\x89\xae\x0d\x6f\xc7\x29\x67\x60\xdf\x21\xbc\xdc\xde\x66\x8d\xfb\x61\x79\xff\xb8\xba\x2f\x77\x84\x99\x0b\x37\x7a\x8b\x74\x1c\xdc\x22\x19\x9e\x26\x16\xa3\x51\x3c\x76\xe5\xd4\x76\x4b\x51\xed\x96\x1f\x33\x62\x53\x70\xeb\x3b\xa6\x54\x01\xa2\x21\x57\xa3\x7a\xad\x78\x88\x8a\xe8\x2d\x14\x0a\xa7\xbe\x63\xde\xac\xdf\x31\xaf\x1c\x3a\x91\x0f\x8c\xa9\x79\xa3\x77\xcc\xb9\x43\x81\x44\xd6\x42\xf5\x57\x11\xd4\x34\xb4\xd3\x18\x29\x0a\x91\x8c\x0e\x1c\xb2\xc0\x87\xfe\xc2\xbd\x55\xb1\xc5\x29\x6d\xdf\x5f\x73\x0a\x5f\xff\x13\x84\x67\x35\xe0\x75\xb1\x37\xf8\x45\xc1\x59\xb6\xb0\x5e\x70\xfe\xe0\x74\xa7\x2e\x53\x1e\x92\x6a\xdd\x86\x6a\xa5\x4e\xad\x7b\x68\x98\x74\x21\x18\xda\x2f\xe8\xcf\x9f\x78\x5c\xe1\x42\x88\x6b\x4d\x10\x17\xdd\x53\xa6\x6b\xe4\x60\x8c\xc5\x6f\x31\x09\x22\x20\xc0\x85\x03\xc6\x7e\x80\x26\x72\x65\x04\x51\x96\x2d\x74\x78\x8f\xc0\x73\xea\xf0\x13\xd1\xa4\x32\x32\xc6\xf0\x67\xc5\xea\xaf\x8e\xec\x7b\xab\x58\xcd\x5b\xc4\xea\x65\x61\xfa\xc8\x81\x29\x04\x14\x88\x6d\xc9\xa5\xc7\x43\xa8\x1d\xf7\x80\x4d\x27\xbf\x22\xd6\x1c\x32\x2e\xbc\xde\x95\x58\xf4\xa6\x61\x54\x7e\x79\x61\xa4\xd5\xbe\x01\x7f\x51\x73\xff\x92\xd0\x34\x77\x9a\xa7\x5a\xd5\x3b\x6b\x77\xb5\x00\xa5\x52\x40\xa3\x3f\x9e\x07\xa9\xfc\x23\xb9\xff\xbd\x64\xc8\x36\x55\xe8\xd7\xee\xcf\x9f\xfb\x21\x49\x91\x70\x8c\xf8\x32\xbc\x36\x1a\x93\x29\xd7\x57\x91\x27\x61\xe0\x8b\x20\xed\x19\x1b\x4c\x8a\x2d\x24\x43\xa6\x41\xe1\x52\x5d\x8e\x69\xcb\x2a\x2c\xe5\x21\xf9\x64\x65\x48\xee\x2b\x2e\x4c\x8b\x03\x1b\xfd\x07\xa3\x59\xcf\x1d\xed\x51\x7d\x72\xcb\x36\xfd\xf6\x16\xb9\xef\xf4\x16\x31\xe0\xb0\xa3\x7c\xac\xcb\xf7\xee\x20\x0e\xb6\x8a\x7d\x95\xd9\xce\x6c\x2b\x5f\x67\x8a\x8b\x32\x72\xe2\x90\x68\x68\x7f\x58\xb1\xe6\x27\x85\xe0\x38\xe4\xbe\xe6\x92\x67\x38\x54\x9b\x39\x7c\xef\xe4\x22\x6a\x03\x0e\xe4\x16\xac\x4d\xf8\x2f\xd3\x8e\xa0\x1a\x3f\xc7\x10\x8e\xea\x84\xb4\xb5\x9a\xfd\x21\x2f\x8d\x5d\x91\xd0\x89\xc3\x29\xa5\x2b\x67\xa2\x75\x63\xa7\x54\x83\x14\xa3\x96\xe4\x38\x86\x19\x99\x46\x60\x24\x8c\x1f\x04\x8e\xb8\xc1\xa4\xf8\x1a\x1b\x6f\xe9\x1c\x35\x12\x1e\x53\x83\xd9\x61\xa5\x6c\x92\x5c\x94\x91\x33\x47\xed\xfb\xca\x02\x1d\x0d\xb6\xd7\x0c\x77\xb5\x6e\x3e\xe8\xb8\x1d\xb3\x67\x6c\xa8\x68\x11\xf4\x1b\x17\x75\x13\xaf\xd3\xed\xf1\xce\x5f\xe1\x3e\xbd\x3b\x21\x29\x46\xfe\x51\xc9\xb2\x99\x5c\x6c\x2f\x31\x99\x9e\x92\xaa\x70\x11\x5e\xfd\x92\x68\x25\xb4\x68\xe5\x96\x82\x94\xb8\xfb\xf3\x42\x3d\xbb\x6e\x42\x70\x84\x7a\xab\x6b\x1c\xf9\x00\xae\xf2\xb7\xd5\x2a\x7f\xab\x56\xf9\xbf\x30\x4b\x95\xac\x56\x04\x4a\x95\xb2\x9a\xb2\x44\x1c\x38\xe4\xdc\x41\xc9\xe4\xd0\x59\x11\xd3\x6a\xa2\xcc\x8e\x43\x27\xa7\x0e\x71\xa9\xa9\x05\x34\xf9\xcb\x56\xbf\x8e\x1d\x3a\x39\x71\x94\x49\x29\x85\xae\xd4\x01\x8a\x92\x19\xa5\xd4\x7c\x1f\xe6\x9a\x66\xea\xe4\xa2\x91\xc4\x0c\x29\x61\x87\xf6\x55\x75\x10\xa7\x77\xa2\xf1\x68\xf4\x7f\x54\xa7\x07\x1d\x2c\xaf\xd7\xf8\xa5\xfc\x9e\x2a\x36\xb8\xe7\x10\xf4\x88\x46\xfe\x67\xce\xc8\x77\x07\x63\x82\xf9\xf7\x25\xa8\x7e\x70\x73\x0a\x9f\xd7\x48\x0a\x52\x46\x78\x89\x42\x3d\x7b\xa2\x20\x0e\xbe\xa2\xe0\xc0\x17\x28\x38\xf0\x13\x44\xc2\x63\xfb\x0a\x62\x7d\x0f\x31\xea\xec\x70\xfd\x61\xa1\xcd\x22\xa7\x57\x17\x0f\x96\x0b\x07\x97\x82\x39\x75\x85\x90\xd5\xc9\xac\x27\x49\x2d\x61\x3c\xee\xd5\xea\xe2\x8d\xe2\x81\x03\xf2\x2a\x83\x11\x84\x8a\x9d\x7c\xf6\xe0\x75\x5a\xae\xc7\xe7\x3a\xe2\x49\x8a\x5b\x58\x6f\xbc\x5a\x8f\xa0\xdf\xcd\x05\x9c\x79\x44\x4c\x0c\x8c\xcc\xeb\x11\x25\xb6\x50\xc3\x54\x37\x8c\xc2\xd4\xf9\xca\xd3\x30\x6d\x0c\x1f\x9f\x91\x57\x8e\x1c\xe9\x1b\x70\x11\x7d\xe3\x7b\x06\x95\x17\x0d\x44\xc3\x13\x78\xef\x15\xf7\x2b\xff\x02\x88\x86\xc7\xf0\xd2\x2b\xcc\x40\x2b\x03\xa2\x09\x45\x7d\x5e\x38\xa9\xde\x1a\x15\x6f\xfd\xe0\x00\xc2\x25\x5d\xe0\x7c\x17\xc5\x41\x51\x1c\x3b\xf0\xc3\x3e\x33\xef\x8d\x72\xed\x6a\x50\xbe\xe6\xe4\x36\xc1\xb5\x3a\xe6\x5e\xf1\xb4\xde\x52\x1b\xcb\xeb\x94\x90\xc4\xba\x87\x58\x13\x63\xb9\xc9\x25\x79\xe1\x04\x15\x4f\xd6\xf9\x49\x6e\xd5\x8d\x48\xbb\xa1\xe7\xb1\x79\x2c\x7a\xcc\xf3\xf4\xb9\xa7\x41\xbf\x98\x6b\xfc\x1e\x1b\x8f\xab\xa0\x9c\xe6\xc3\xc5\x67\x3e\xf7\x60\x97\x7c\xc8\x60\x0a\x1c\x62\x29\x1e\x28\xc6\xfb\x52\x99\xd9\x2f\xc7\x06\x85\xf7\x4e\x23\x9e\xe2\xa5\x53\xc5\x53\x04\x61\x52\x1c\xc0\xea\x16\xbf\xdd\x62\x50\x78\x73\x8b\x80\xf0\xcc\x59\x0f\x42\xf4\x1c\xb7\xdf\x47\x39\xbc\x73\x34\x96\xff\x0b\xbc\x18\x8f\x72\xf8\xe8\xdc\x12\xc4\xf1\x09\xab\x3e\xce\xe1\x35\x5e\x6c\xe7\x10\xf4\x3b\x7d\x4a\x6a\x76\x84\xd1\x1f\x16\xa6\x0a\x2b\xd3\x84\x15\x2a\x28\x2a\xe2\x1a\x44\x38\x00\xd7\x8a\x20\xb4\xa4\xc2\x20\x50\x0b\x4f\x13\xc4\xa7\x87\xd8\xd2\x19\x68\x64\xeb\x8c\x3e\x0d\x2c\x1b\x22\xcb\x85\xc4\x0a\x41\x58\x53\x48\x2d\x0e\xcc\x8a\xf3\x9c\x42\xd4\x5f\x8b\xa4\xd0\xf3\x48\xd0\xc7\xb0\x69\x4c\x15\x1e\x51\x04\x80\x3a\x01\xcc\x5d\x13\x94\xb0\xf6\x49\xbf\x2b\x40\x03\x13\x4f\x3c\x82\x19\xf1\xa7\x30\x23\x73\x9d\x12\x77\xbc\xbd\x3d\xa2\x74\x25\x8f\xfc\x12\x7e\xd6\xf6\x72\xb2\xff\x25\xd0\xb5\x87\x4b\x88\x1f\xa3\xe5\x14\xff\xcb\xc1\x1e\x9b\x98\xac\xbb\xff\x3f\x94\xeb\x7d\xa9\x33\x8f\xf2\x1c\xd2\x7e\x67\xe2\xf0\x84\x04\xf4\x8f\x47\x93\xc8\x9c\x91\xb4\x0f\x33\xb2\x13\xc2\x23\xa9\x04\xcd\x08\x63\x10\xa9\x95\x71\xa0\xee\x69\x13\x2a\xeb\x4b\x1a\xdb\xca\xc1\xee\x77\x66\x0c\xda\x2c\x12\x06\xb9\xfd\xdb\xe3\xaa\x16\x89\x59\x64\xb8\x58\x24\x2a\xbb\x0b\x86\x58\x95\xe9\x2d\xc2\x46\x23\x02\x7d\x2f\xca\xdc\xe1\xcc\x9a\x13\xbb\x4f\x02\x0a\x76\x9f\xa4\x94\x4e\x0c\x74\xf0\xf1\xc3\x20\xb9\x34\x4c\xc3\xe8\xce\x26\x53\x4b\xbc\x12\x94\x09\x3f\x22\xaa\x53\xca\xac\x81\x33\x32\x0c\xec\xf0\x8c\x28\x5f\xd0\x94\x4e\x22\xd3\x30\x72\xe5\xdd\x83\x30\xd9\x2e\x18\x3d\x11\xa0\x28\x52\xdc\xfa\x06\x46\x0f\x6d\xaa\x21\x86\x74\xe3\x42\xc2\x82\x05\x18\x3d\xad\xca\x42\xdc\x8e\x32\xcd\x16\xd8\x68\x17\xc2\xb4\x61\x94\x3e\x28\x5c\x67\xb4\xd1\x7d\xc3\xde\x81\xfc\x11\x49\x0d\x49\x27\x12\xfc\xf9\x73\x13\x61\x2d\x78\xf5\xbc\xbe\xe8\x71\x91\x5c\x0b\x11\x18\x39\xa1\x18\x0d\x39\x73\xe1\x88\x60\xa2\x43\xb9\x83\xb9\xfd\xba\xa8\x58\x3b\x09\xe6\x10\x22\xe6\x44\xd9\xd3\x56\x93\x9b\xc3\x12\xd1\xe3\xcc\xbe\x32\x36\x88\x37\x64\xf2\x1f\xbe\x11\xd3\x56\x5d\x4f\x56\x9d\x46\x61\x90\x18\x1b\x64\xba\x41\xf8\x06\x09\x37\x18\xd5\x3a\x68\x0a\x91\xa5\x6d\xa8\x49\x0e\x35\x7b\x35\x8e\x6d\x69\x6d\x8a\x32\xc2\xfa\x95\x60\xbe\x23\x29\x6b\x81\x59\xa6\x52\x5a\x13\xc6\xa7\xfd\x75\x56\xed\x86\x38\x73\x52\xf8\x2e\x85\xfd\x22\xa7\xb8\x6e\x84\xf7\x6f\x33\x32\xe1\x27\xb5\x6a\xf7\x81\x3e\xf7\xec\xdf\x66\xbe\x51\x40\xc2\x10\x83\x67\x11\xd7\x7a\xce\x51\x3d\x80\xd0\xba\x20\x51\xbf\x4c\xec\xe5\x02\x11\x96\xe8\x93\x19\x49\xfa\xf8\x1b\xc5\x1e\x95\x39\xea\xd1\x40\xe8\x5b\x92\x32\xab\xa5\x8a\xb8\x58\xb5\x67\xa6\x94\x42\x6a\x95\xf9\xa6\xc8\x23\xcb\xb2\xd8\x64\x64\x32\xaa\x4a\x81\x37\xdf\x99\xca\x7b\x76\xf3\x9e\x7c\x0d\x9c\x13\x8e\x9e\x61\x21\xe6\x5e\xb0\x90\xc9\x78\x70\x42\xbb\x4e\x50\x67\x69\x9c\xb8\xd3\x45\x79\x72\xb9\x7c\x4e\x50\xf3\x60\x15\xe2\xaa\x26\x34\xaa\x73\xd5\x3e\xba\x15\x1c\xa7\x52\x91\x78\x83\xea\xc4\x49\x2a\x35\x87\x33\x29\x70\x19\x27\x97\xa9\x01\xc6\xf3\xc8\x35\xc0\x38\x66\x89\x0a\x85\x5a\x9e\x22\x7c\x35\x73\x03\x5c\xa4\x24\xb6\x5e\x3b\x0d\x02\x4b\x13\xa4\x2f\x4d\xb5\x9a\x1a\xa6\x9a\x1a\xb2\x82\x1a\x3c\xe4\x91\xa3\x1c\xb2\xbe\xce\xb6\xe0\xf4\x55\xd4\x9f\x6c\xb5\xaf\xae\xe7\x52\x29\xea\xaf\x3a\xa3\x40\x52\x4f\x28\x16\x60\x42\xb1\x36\xa3\x25\xf3\x84\x14\xd2\xbe\xf6\x14\xaf\xd3\x63\x44\x22\x2b\x59\xb1\xa0\x61\x8d\x15\x19\xbb\xe6\x09\x17\x89\x6c\x80\x95\xf4\x61\x4d\x39\xf0\x72\x11\x65\xfd\xf2\x91\x7e\xbf\xb4\xe5\x44\x91\x54\xeb\xba\x0e\x0f\x59\x70\xe1\x09\x0c\xc3\x93\xbf\xb6\x6e\x7a\x4a\x63\x1e\xd4\xf5\xe5\x93\x36\xe1\x57\x75\x15\x4d\x61\x4b\x5d\x69\x2e\xe4\xaf\xd3\x22\xf5\x19\xcc\x88\xd3\x87\x13\x2d\x15\xde\x61\xd3\x35\x5e\xb1\x20\x65\xd1\xc2\x68\xee\xbd\xc6\x73\xc1\xa3\xda\xfd\x62\x0f\x36\xde\xb0\xc8\xbe\x34\x9a\x1b\xb1\xb1\x33\x8f\x5c\xcf\x68\xee\xc6\xc6\x1b\x56\x3c\xfc\xa0\x7c\x57\x1a\x08\xa3\x19\x18\x6f\xbc\x4a\xbd\xa2\xde\xa3\xb2\xbd\xf4\x22\x8d\x13\xa3\x09\xef\x6d\x1c\x8b\x79\x22\x7c\x2e\x22\xa3\x99\xce\xdc\x38\xb2\x93\xb0\xba\x3d\x2e\x3f\xed\x6d\x98\xe9\xfa\x4d\x39\xc0\xd8\x13\xb6\x2a\xc8\x73\x32\x23\x3b\xe5\xe8\x2d\x8f\x7f\x80\x1c\xaa\x8b\x14\xbc\x3f\x4d\x0a\xa8\xae\xde\x4e\x0b\x7a\x4d\xc6\x7d\x0c\x2c\x51\xc1\x5d\xdd\xfc\xb9\x10\xc0\x81\x9b\x11\xd8\x2a\x29\xfa\xc5\xda\xea\x0f\x96\xab\xcf\x3b\x18\xf7\x34\x02\xc3\x67\x37\x9e\x08\x2e\xa4\x8a\xbe\xa3\xd0\x76\xe0\x5a\xad\xdd\x38\x89\xc2\xe0\xc2\xa0\xb0\xe8\x77\x8b\x17\x5e\x3b\x48\xc5\xb0\x3f\xc9\x98\x82\x9a\xb9\x14\x2a\x00\x5d\x39\x13\x21\x64\x52\x4e\xe1\xa6\x7f\x5b\x3e\xf4\x5a\x2a\x74\x62\xd8\x25\xc2\xbf\x1d\x06\x99\x88\x92\x5e\x9c\x44\x18\xe4\x0c\xfb\x7d\x6b\x46\x16\x7d\x88\x1c\xa5\x1c\x1e\x08\xb8\xe9\x53\x0a\x57\xfd\xe6\xc9\x9e\x68\xdd\xb1\x24\xe7\x48\x5c\x5f\xcc\x5d\xfb\xaa\xce\x37\xae\xcb\x99\x8f\x53\x3e\x13\x76\x52\x5b\x9b\x62\x62\xec\x07\x8e\x61\x1a\xc7\x85\x75\xbe\x49\x5e\x97\x61\x1a\xb5\x9d\x9d\xa4\xf3\x81\x8a\x88\x6e\xa3\xba\x5d\x72\xd9\x07\x01\x23\x18\xd3\x5b\xa8\x4c\x1f\xe6\x9d\xe8\xf7\xbe\xd5\x11\x15\xd5\xd9\x26\x0e\xf4\x8c\x5c\x60\x7b\x72\x80\x28\x9a\x8b\x6a\x42\x8d\x2b\x35\x21\x2d\x7c\x25\x43\x36\x7b\x5a\x97\xfc\x46\xe8\x6f\x5d\xe4\xba\x44\xec\xc0\x5c\xc9\x5e\xc9\x90\x7d\xaf\xa7\x75\x59\xaa\xaa\x20\x03\x08\x95\x04\x47\x36\x95\x89\x28\x73\xc5\x75\x0b\x93\x3b\x69\x1a\xf2\xd1\xe2\x73\x87\xb1\x19\xdc\x3a\x38\xe8\xe7\xd6\xc9\x78\xed\xd0\x5b\x7d\x43\x65\xd5\x34\x57\xe7\x52\x2a\xf5\x89\xf8\xb3\xb3\x39\xfe\x8b\x67\x73\xfc\xe7\x67\xf3\xea\xee\xb3\x79\xb5\x76\x36\xff\xfc\xfc\x8d\xff\xe5\xf9\x93\x2b\xb5\x83\xa2\xd4\x14\x92\xa0\x9b\x55\x29\x4c\xa3\x2e\xfb\x66\xa4\x94\x9e\x19\xd9\x4f\xe1\x31\x9c\x4c\x15\x2b\x54\xcc\x4a\x4c\xa4\xba\x26\x87\x56\xfe\xe3\x52\x53\xff\xfc\x2e\xff\x59\x94\x72\x36\x6a\x28\x41\x4e\x61\xa7\x45\xe2\xa9\x26\xe5\xd5\xa4\x23\xda\x20\x74\x98\xd7\x9b\x32\x47\x14\xe6\xe4\x0e\xc3\xea\xaa\x6c\x83\x8f\x0e\x1c\x97\x79\xe1\x45\xaf\xfe\x43\x8f\x50\x25\x8a\xaf\x3e\xa5\xc5\xd0\xee\x0a\xcb\x22\x55\x35\xed\xb6\x17\xc6\xa2\x76\x56\x11\x65\xe4\x99\x43\x5e\x38\xf5\x13\xb6\x1b\xa3\x5d\x02\x92\x2d\xf3\xd0\x59\x54\xed\xbe\xf2\xe0\xa3\x03\x44\xaa\x78\x19\xac\x06\x72\xd5\x64\x56\xf5\x84\xdf\x27\x51\xb3\xd5\x79\x32\xd8\xee\xdd\x45\xc4\xbe\xea\x03\x26\x72\xd3\x57\xe3\x62\x57\xee\xe8\xe7\x34\x0c\x93\xf6\x11\xf0\xbd\xc1\x66\x6f\xc5\xb4\xa8\x8e\x8e\x7b\x7e\xb4\x6e\x60\x76\x59\x60\xab\xf0\x9c\xe6\x5a\x6a\x34\x59\x79\x01\xa8\x26\x3e\x35\x9a\x38\x16\x49\x6f\x8f\x25\xe2\xfe\x89\xeb\xd7\xdd\xd4\xba\x07\x9c\xd9\x57\x4e\x14\xce\xeb\x54\x56\xac\x35\xb3\xa8\xae\x4f\x7f\x3c\x77\x8e\x47\x15\x76\x42\x46\x80\xff\x51\xa3\xe5\x2c\x63\xea\xde\xac\xa1\x2e\x7c\x51\x9b\xd5\xbf\xa5\x3f\x55\x57\x72\x38\xee\xaf\x37\x35\xce\xfa\x6d\x19\x3a\x35\xf6\x0d\x6d\x09\x9d\xec\x0a\x42\x6e\x44\x3b\x15\x6e\x0f\xad\xd1\x61\x52\x5c\x5f\x17\x1a\xd6\x2c\x6f\x8d\x0b\x53\x55\x9a\x2e\x6d\x15\xf2\x44\x9b\x7f\xdc\xaf\x75\x3b\xd2\x6e\x64\x4b\xc1\x51\xad\x0a\x79\x54\x19\x07\x76\xd7\x28\xe5\x56\x57\x98\xb0\x42\x07\xb3\x14\x96\xf6\x90\x41\x30\xe4\x38\x73\xe7\x84\x24\xb7\xc4\x94\x16\x51\x46\x18\x1e\x9a\x0c\xf9\xaa\x25\x65\x7d\x7c\xe8\x9f\x8b\xfe\xac\xc5\x7a\x46\x3a\xd6\x33\xd2\xb1\x9e\x97\x19\xea\xb6\x65\x0c\x27\x1e\x94\x3c\x04\xd1\x88\xe1\x14\x72\x3f\x54\xc1\x92\x4d\xb8\x85\xbb\x07\x4b\x46\xdd\xc1\x92\xb3\x3e\xa2\x35\xa4\xc5\x9c\x1c\xac\x91\xb9\x6b\x0c\x8f\x8d\x7a\x15\x58\x04\x36\xb4\x8b\x76\x42\x15\x2b\x75\xd4\xbf\x0b\xd8\x4f\x19\x00\x5f\xcc\xc2\x7e\x48\x12\x3a\x59\x19\x4c\xa3\xae\x16\x9d\x94\x62\xf2\x49\x15\x19\x58\x65\x11\xaa\xf9\x80\x68\xcf\xd9\x5f\x6e\x6e\xa7\xd9\x96\xd9\x43\x2c\xab\x23\x75\xf2\x5d\x72\xb8\x83\x52\x89\x5a\xca\x02\xa2\xc6\x78\xc9\xf2\x5c\x03\x2d\x5a\xc9\x40\x7c\x77\x38\x25\x15\xce\x93\x53\xf8\xda\xef\x4e\x73\xd1\x02\xa7\x54\xef\xd2\xa8\xc2\xd6\x7e\xe5\xc1\x71\x1f\x66\xe4\x48\x7d\xca\x72\x8a\x73\x0d\xab\xb4\x6c\xf3\xfe\xee\x61\xb2\x98\xbe\x65\xf8\xc9\xe0\x81\x01\xe7\x7d\x8c\xa6\xb8\x4c\x7c\xef\x79\x28\xe5\xae\x93\x7e\x13\xd7\xb6\xd5\x62\x77\x4e\x3e\xf4\x41\x07\xb8\x4f\x8c\x5e\xc3\x0b\xca\xa0\x4b\x81\x6a\xe7\xfd\x76\x47\xf9\x9a\xce\x54\xce\xde\x1b\x55\x18\xf7\xd4\x06\x87\x13\x8a\xf3\x58\xd1\x48\x11\xa6\x1a\xd7\xdc\xac\xd5\xc9\xa3\x98\xd6\xce\xf6\xc6\x28\x85\x41\x53\xde\x2d\x62\xf2\xb5\xd4\xdb\x31\x8d\x75\x5f\xc6\xc1\x54\x08\x07\x0d\xb3\xcb\x46\xc9\xc6\xec\xe4\x44\x2f\xc0\xb7\x85\x55\xeb\x54\xea\x97\x6b\xce\x11\xb5\x9f\x98\x32\xc5\xd6\x5d\xf4\xde\x45\x4a\x56\xdd\xa9\xd6\x02\x1c\xde\x69\x59\x4b\x9e\xd6\x33\x36\x3e\x14\x86\x88\xd3\x7e\xe5\x95\xd4\x9f\x18\x88\x98\x27\x0c\xd3\x38\x9d\x3b\x2a\xcf\xc2\x9d\xc4\x87\xb7\xfd\x25\x12\x5e\x23\x77\xd4\xdd\xf2\xa2\x86\xdf\x47\x2c\x12\xa3\x2e\xef\x26\x20\x72\x0a\x7b\x38\x5a\x4f\x72\x38\xeb\xaf\xf7\x05\xfe\xde\x5f\xef\x44\xf4\xaa\xbf\xfe\x0c\xf1\x73\x71\x32\xf3\xb2\x7f\x4b\x44\x39\x1b\x32\xa7\x80\x8d\xb4\x6b\x69\x07\xdb\xcc\xd6\xca\x79\x5b\xa9\x14\xa1\x97\xfa\x2a\x37\xad\xf6\x87\xac\x79\x03\x16\x80\x5a\xc5\xa2\x58\x65\x5b\x51\xc5\x9a\x02\x79\x6b\xea\x10\xa6\xb2\xcb\xa2\x0b\xd7\x01\x7a\x6d\x2c\xd3\x66\xaf\x41\xa8\x25\x45\x15\xe2\xd0\x0a\xc7\xb8\x6b\xcf\xff\x3d\xbd\xad\x75\xac\xce\x4c\x5d\xcb\x6e\x5f\x85\xb7\x8f\xae\xc6\xf9\xf8\xef\x18\xdc\x82\xb0\x57\x25\xd2\xdb\x98\x85\x5b\x08\x4c\x39\x85\xf7\xb7\x1d\xa7\xd4\xac\x4b\xb5\x75\xec\x91\x97\x7d\x78\x9b\x81\x36\x1c\x81\x61\x87\xde\xc0\xbb\x18\x6c\xa3\x67\xee\x43\x0d\x92\xfc\xaa\x0f\xcf\x1c\x0a\xcf\x1c\xf2\xb9\x4f\x21\xa0\x50\x3e\xb6\xa7\x33\x27\x57\x4f\x6e\x35\x9e\x3c\x6b\x3c\x99\xd4\x9e\xdc\xc7\xb0\xd7\xd6\xd7\x7d\x6f\x3c\x14\xb5\x0c\x8a\x9a\x28\xfd\xf0\x58\x3f\xbc\x32\x53\x92\x3d\xfc\x3f\xff\xf7\xaa\x3e\xd3\x98\x8b\x65\xee\xa9\x19\xd4\x8a\xb5\x54\xab\x3b\x7b\xfd\x6e\x7b\x41\x71\x36\xb0\x6c\x5a\xcd\x29\x7c\xeb\x77\x67\x39\x47\xab\xe7\xfd\xff\x22\x61\xf0\x53\xf6\x6c\x07\x6b\xf4\x69\x81\x62\x27\xac\x80\x4e\x0c\x87\x25\x6c\x60\x6c\x08\x53\xc0\xfd\xff\xfa\x67\xfc\x3b\xa9\xe1\xdd\xfd\x94\x85\xa6\x94\xa9\xff\x79\x5f\xee\xb6\xe5\xa3\x89\x15\xa1\x53\x68\x52\x67\x8c\xaa\xa9\x8b\x88\xf9\xfe\x57\xe1\xb8\x08\x74\x5a\x40\xa4\xc3\x9b\x7e\x17\x80\x5a\x81\x9c\x16\xfd\x33\xf8\xf9\xcf\xe8\xe7\x3f\x03\x05\xa0\xf6\x6c\x8d\x21\x37\x0a\xaf\xe3\xca\x86\xfb\x5c\xd9\x70\x65\x37\x59\x24\x98\x41\xe1\x5d\x97\x7b\x82\xca\x4d\xb0\x4b\xa6\x1c\xb6\x60\xfc\x00\x8e\x12\xf2\xa6\x4f\x52\x04\xa8\xa7\x80\x79\xf4\xff\x1d\x8c\x34\x5a\xbf\xd6\x83\x9a\x9f\x4b\x5f\x2f\xf6\xb4\x58\xec\x09\x2e\x76\x71\x67\x4e\x0a\xcf\xfa\x84\x49\xba\xf8\x0b\x58\xea\xbf\xa5\xdf\x6d\x5d\xfc\xab\x99\xeb\x7f\xc3\x80\x97\x62\x43\xe3\x63\xfe\x34\x9b\x7d\xd1\x6f\x45\x09\x50\xd8\x8b\x62\xc8\xb6\x81\xc9\x3f\x5f\xc1\x96\x7f\xfa\xe0\x5a\x62\xc8\x0f\x21\x94\xbf\x0e\x60\x2a\xff\xec\xa2\x0b\x5f\x7f\x72\x44\x8c\xb7\xe2\xba\xc8\x6a\x2a\x59\xdf\x69\x0a\x89\xd4\x93\xcc\x23\x62\xec\x3b\x6e\x52\x95\x1d\xe9\x8c\x39\x98\x52\x88\xb7\x79\xfd\xd5\xfc\xa8\xf8\x90\xe1\xa8\xed\x92\xf7\x7d\x48\x31\x5f\xf3\x90\x9d\x41\x3a\xc4\x28\xd7\x93\x3e\xd8\xc0\x6a\x8c\xb8\x44\x3b\xfe\xd0\x57\xec\xf7\x8d\x53\xb0\xdf\x77\x0e\x95\xcf\x9e\x52\xb8\x20\xef\xfa\x60\xec\x6a\x80\xf4\xb2\xea\xb7\xb2\xea\x73\x55\xf5\xb8\x31\xb4\xe5\x36\xb3\x4b\xbe\xf6\x61\xaa\xa2\x1c\x66\xe4\x50\xaa\x15\x31\xf6\x71\xa7\x4f\x0a\x27\xb1\x8f\x7d\x2b\x8d\xe0\x53\xdf\x62\x11\xbc\x6e\xe5\x2a\x51\x44\x78\x84\xcc\x44\x43\x84\x06\xfe\x1d\xe3\xc9\xa2\xce\x8a\xfc\x31\xea\xbe\x3b\x91\xe8\x2d\xc2\xb4\x17\xa7\xfa\xe2\x9a\x05\x49\x2f\x09\x7b\xe2\x66\xee\x46\xa2\xa1\x16\x4c\x0c\x0a\x6c\xcb\x5c\x1f\x22\x13\x65\xe4\x3c\x25\x33\x12\xf8\xa8\xc8\x37\xcc\x6c\x61\x30\x75\x23\x5f\xed\x4b\x3c\x34\xcf\x53\xf2\x35\xa5\x60\x6f\x9a\xc6\xbe\x7a\x5b\x31\xef\xb2\xeb\x89\xdf\x2d\x9f\xb7\x19\x54\x7a\xb7\x42\x72\x05\x88\xb7\x39\x93\x62\xb4\x1e\x7a\xe1\xaf\x17\x71\xd3\xce\x3e\x7c\xca\x48\x40\x37\x8c\xdf\x34\x74\xbe\x02\x8e\xc3\xa4\xac\xcc\x6f\xc5\x80\xaf\xd2\x9d\x35\x12\x49\x62\x92\x71\x95\x58\x00\xc3\x73\xad\x5f\x44\x91\xab\x6b\x04\xfb\x98\x9e\xa0\x16\xe7\xa2\x80\xea\xde\x4d\x12\xf3\x17\x5b\x9d\x91\xd4\x97\x5d\x9b\xa9\x64\xe6\x4d\x6f\x73\xa5\xf2\x28\xe3\xa0\xed\xb7\x3a\x14\x60\x1a\x19\x74\x10\x9a\x52\x15\x08\x56\xe3\x98\xc7\x09\xdc\x0b\x86\xfc\xe2\xb7\xdf\x92\x89\x61\x19\xa6\xbc\xfe\xf9\x33\x99\x54\xf7\xfe\x4f\xc3\x34\xee\xe1\x3f\x85\x51\x8b\x63\x77\xce\xf1\x9d\xee\x9d\xdf\x09\xc2\x3a\x4f\xc9\x7e\xbc\x84\x57\xcc\x7d\x38\x32\xcb\x2e\x8c\x56\x3a\xa0\x20\x29\x14\x9e\xf1\x79\xde\x88\x0f\x98\xf5\xe1\x1a\xd1\x91\x6c\x5f\x6d\xee\xa1\xaf\x3c\x3c\x1f\x18\x14\xa6\xcd\x8e\xb5\x59\x41\xff\x53\xcc\xba\x35\x14\x21\x1e\xaa\x24\xf7\x43\xfe\x18\x74\xd6\xcd\x2d\xe5\x96\x3d\xb4\x37\x6f\x01\x65\xfa\xff\xc9\x31\x49\xe8\x37\xcb\x35\xea\x72\x49\xd5\xe9\x8a\xa4\x8c\xc7\x29\xab\x3a\x77\x15\x01\x77\xcb\x11\x4a\x72\x97\xd3\x0b\xf1\x2f\x1c\x11\xe4\xc0\xd7\xf0\xc7\xff\x4c\x68\xbf\xd5\x04\x06\x3a\x9d\xf3\xaa\x1c\x9b\xf8\xa8\x28\xc5\x98\xb0\xea\x6c\xd9\x0e\xa7\xca\x51\x73\xc3\x1a\xfc\x68\xc5\x26\xa7\x9b\xc0\x6d\xc5\xd1\xad\x60\xfe\x03\xcc\x6e\xc5\x6d\xf8\x45\x8e\xd8\x84\xba\x4c\x6a\x34\xf1\x51\x1f\xc4\x52\xc9\xfa\x49\x44\x5b\x93\x9d\x36\xbe\x73\xbd\x61\xf4\xf6\x10\xcd\x25\x14\xdf\xf3\x94\x08\xe4\x46\xf5\xad\x00\x3f\xdc\x68\x08\xaf\x7f\x65\xfb\x7b\xc2\x13\xc5\x26\x90\x2b\x63\x40\x83\x80\x2b\x23\xb8\xeb\xcb\x09\x9a\x51\xc9\x1e\x49\xa0\x92\x99\x44\x3e\x44\x70\x6f\xac\x52\x99\x7c\xa9\x27\x79\xf2\x5b\xf2\xea\xe8\x31\x4c\x96\xec\xe4\xc2\xaa\x21\x0c\xa5\x8d\x2c\x2b\xad\x6e\x30\xec\x26\x57\xa1\x64\x6b\x63\xc4\xf8\x49\xae\x63\xc3\x40\xa0\xff\xa7\x0a\x30\xd4\x90\x69\x05\x09\x14\xde\xfa\xe6\x8c\xbc\xee\xaf\x62\xcf\x55\x5f\xdf\x0e\x64\xa4\xe8\x8f\xfb\x05\xd8\xa3\xbc\x41\xa9\x42\x3f\x4a\xdb\xac\xce\x49\xbb\xd5\x19\xa5\xef\x9c\x82\xe7\xd7\x73\x86\x67\xfe\x2d\xa0\x12\xfe\x3a\x57\xf1\xd2\x3d\x4d\x87\x02\x2e\x39\xa7\xcd\x45\xe0\xb8\xc1\xc5\x8a\xbf\x97\xd0\x2b\x2d\xcf\xa1\xef\x77\x5b\x64\x30\x20\x26\x29\x32\x96\x65\x3e\x9c\xa7\xcb\xf6\xe4\xa8\xb4\x24\xd7\x52\x3a\xa9\xcc\x09\x8e\x5f\xc4\xda\xd5\x4e\x13\x99\x73\x21\x7a\xf8\xef\x60\xee\x7a\x5e\x78\xad\x7f\xe8\x0e\x6a\x76\x84\x72\x62\x12\xce\x1b\xa8\x26\xca\xb9\x2f\xd0\x2c\x38\xef\x78\xdd\x17\x74\xbd\xc8\x29\xf8\xfe\x8a\x19\xdf\x9d\x92\x2d\xbd\xc7\xff\x68\x39\x3d\xec\x08\x2b\x2a\x79\x69\x37\xf0\x6f\xdf\xc7\xa4\x68\xf6\xa5\x94\x7b\x4e\x10\x25\xb2\xec\xe0\x1d\xdb\x9d\xa9\x46\x46\x92\x3e\xb0\xff\x97\xff\xc9\xca\xc0\x49\xaa\x11\x91\x6d\xd0\xb4\x9a\xe4\xb4\x5d\x39\x28\xd9\xc5\x85\xaf\xe3\x4f\xe6\x4a\x0a\xe3\x06\x85\x6b\xff\x2e\x66\xfd\x9a\x62\xde\x70\x26\xac\x40\x45\xec\xd0\x1b\x6c\xa2\x81\x0d\xeb\x36\x00\x3c\x67\x64\xee\xb7\x29\xeb\x0d\xef\xa6\xc1\x78\x74\x3b\x14\x49\x54\x1a\xca\x16\xfe\x1a\x05\xbb\x0b\xc5\xf3\xa4\xcc\xd1\xab\x51\x3c\x8f\x94\x6b\x30\xbd\x45\x53\xae\xf0\x74\x60\x09\xba\xb3\x0c\x99\x63\x92\xf8\xff\xdb\xf7\xb2\x93\x94\x5c\xf8\xff\xae\x8d\x6c\xa5\xf1\xe6\x2e\x96\x54\x13\x79\xed\x83\x71\xb0\x67\xc0\x99\x64\xbd\xc8\x9b\xd5\x3d\x25\x72\xf4\x58\x82\x45\xb3\x4c\x96\x1e\xd1\xb2\x58\x4a\x2c\x8d\x42\x76\x56\x15\xaa\x13\x22\xa7\xf9\xf0\xc7\xaa\x5c\x1d\x25\x39\x3d\xbe\xd0\xef\x65\xa7\x55\x59\x61\x7f\x50\x05\xc7\xf5\x0e\x25\x02\x6f\x4b\x66\xa5\x67\xa6\x2c\x2d\x4e\xfe\x8c\xe6\xf9\xb6\x64\xbd\xb6\xaf\xcf\xb9\x29\x24\x2a\x9b\x3e\xa4\x72\x87\x16\x6a\x87\xbe\xf4\x21\x81\x7b\xa3\x72\x87\xce\x29\xdc\x68\x4d\x67\xd3\xa0\xb0\xef\xb7\x1b\x3f\xaf\xb3\x55\x25\xa1\xb1\x68\x96\xee\xe1\x59\x35\xf3\x85\x59\x9d\x4d\x06\x3a\x46\x1c\x7e\xa5\x8d\x1d\x95\x8b\xbe\xd1\x0c\x7b\x51\x22\x55\x5c\xb5\x6b\x8c\xa8\x09\x22\xfe\xe2\x7b\x05\x2e\xf3\xed\x69\xdd\xc2\xa0\xbf\xe4\xa6\x5a\xea\xc6\xae\xca\x72\xde\x3b\xd6\x89\xea\xbe\xac\x9c\x86\x26\x8d\xec\x18\x72\x45\x94\xce\x80\x4f\x7f\x81\x0f\x55\x9f\x29\x39\x49\xec\x37\xc1\x87\x70\xc8\x8c\x56\xa6\x13\xfb\x83\xf1\xa8\x05\xeb\x53\x8a\xbe\xff\xfa\x8b\xd5\x77\xdf\xe5\xd5\x05\x5b\x21\x91\x14\x4d\x8e\xf4\x3e\x6d\x48\x9a\x82\x55\x3d\x40\x2c\x73\x93\xe2\x81\x0a\xfb\xe3\xde\x68\x99\xb9\x94\x75\x0a\xb7\x00\xac\xb3\x92\x6a\x59\x57\xd2\xf6\x50\xc4\x90\xc4\x93\x65\xa9\x04\x29\xb3\x4c\xcf\x50\x0b\x23\x14\x0a\x41\xe0\xd8\x55\xb0\x00\xd5\x87\xdf\xc5\xcb\x3f\x12\xcc\x59\xf1\xf1\x8f\x45\x22\x19\xd2\xaa\xbc\x54\x82\x76\xe6\x39\x11\x75\x35\xb0\x49\x4e\x69\x07\x39\xa5\x7f\x25\x39\xbd\x13\x22\xaa\x26\x95\x65\xed\x93\x8a\x43\xb4\xef\x43\x50\xd0\x13\x2e\xad\x1d\xc5\x15\xec\xd0\x91\x9b\xc9\xb1\xfa\x35\x8f\x70\x67\xf1\x3b\x63\x94\xda\x76\xa4\xda\x92\xfa\xd7\x3f\xe9\x74\x9e\xb8\x77\x5e\x23\x0b\x2e\xb9\xce\x59\x39\x05\x57\xbe\x64\x1f\xef\x15\xfe\xc8\x90\x7f\x86\x2e\x76\xf0\x51\x44\xb1\x1b\x06\xbd\x83\x40\xf6\x92\x15\x30\xbb\x7f\xc5\x07\x3c\x8b\x58\x60\x5f\xde\xf1\x03\x92\x21\x7b\xd3\x26\x85\xfc\xc9\x57\xa7\xae\xe7\xec\xb1\x44\xdc\xfd\xed\x6f\xff\xe2\xb7\x9f\xc6\x22\xba\xfb\xdb\x8f\xfe\xba\xb7\xbf\x08\xf5\x9c\xde\xfd\xed\x8f\xff\xba\xb7\x7f\x10\x99\xfb\x4b\x2f\xe7\x7b\x7f\xdd\xcb\x7f\xf5\xc3\xf9\xa7\x7a\x0c\x0d\x5a\x5e\xd9\xc9\x90\xcf\x1b\x41\xff\x8d\xcd\x53\x4a\xfc\x17\x45\xf3\xc7\x65\x67\xe6\x35\xe4\x8a\x06\x34\xf4\xdf\xa6\x8f\xa6\x8f\xa6\x4f\x1a\xb0\xd0\x83\x29\xf3\x5d\x6f\x61\x80\xe1\x87\x41\xa8\x30\xe5\xcb\x0f\xdc\xf1\x57\xfc\x13\x34\x3c\xcf\x53\xbd\xe7\xe7\xb0\xdb\x2a\x0b\x14\x41\x8f\x56\x30\xb4\x4f\x57\x4f\x58\x1f\x56\x32\xe7\x73\x0f\x66\x68\x8c\x7e\x3f\xe4\x1f\xe8\x52\x38\x74\x2b\x38\xf2\x6b\x65\x5f\x3d\x50\xd6\xd5\x5d\x25\x6a\x1c\x3c\xed\x70\xff\x63\x75\x0f\xaa\x03\xb2\xf0\x41\x40\x02\x0c\xee\xdd\x4b\xcb\xa3\xd2\x4e\x4f\xba\xe5\xf4\x7f\x24\x18\xda\x9f\x57\x4f\x58\x3f\x3b\xf2\x03\xb6\xc0\x2e\x53\x0a\x96\x01\xde\x89\xb2\xa1\xdb\x9f\xe8\x90\x7d\x55\xe8\xb7\x27\x88\x7e\xcb\x6e\x54\x72\xb5\x03\xe8\x04\xe8\xdf\x6e\x85\x53\x57\xfe\xb0\xeb\x1d\xd6\x96\x71\x33\x2a\x7c\x89\xfd\x18\x4d\x04\x0d\x1f\x34\x15\x05\x0b\xbb\xe4\x63\x1f\x7c\x1f\x4f\xce\xe1\x80\x7c\xea\x43\xec\x03\xc3\x9f\xe5\xb1\xf2\x56\xc3\xb7\xef\x43\x0a\x07\xe4\x45\x1f\x16\x89\xfc\x74\xa9\x5e\x23\x18\xd9\x39\x5d\x35\x30\xd6\x6a\x5f\x27\x44\x0e\x14\x9c\x62\xd6\xd4\x7a\xfd\x47\xdd\x53\xf0\xde\xc9\x73\x38\xd0\x22\xb3\x36\x47\xc3\x91\xfa\x1d\xb0\xcc\xa0\xf0\xd5\xb7\x7e\xec\x99\xc6\xdf\xee\x17\x99\x14\xb8\x6f\x6a\xc7\x3c\x23\x87\x0f\xaa\x54\xdd\x35\x72\x38\x2f\x6a\x57\x47\x47\xb2\xe4\xb8\xf8\x95\xc3\x49\x59\x43\xed\xa4\xaa\x5c\x5d\xe7\xf0\xd6\xef\x4e\x59\xd6\xaa\xe4\xf5\x97\x45\xb2\xaf\xfe\x92\xfc\xf5\xc1\x2f\x46\x4d\x0f\xb5\xa6\xa4\xe6\x92\x38\xf7\x97\xd2\xf4\x9e\xf8\xcb\x63\xf5\xc1\x97\x94\x4a\x21\xa2\x13\xa3\x57\x81\x94\xe6\x14\x4e\x6f\xb5\x71\x37\x70\xe9\x37\x66\xe4\xad\xb6\x34\xac\xe2\xd2\xd6\xf0\xe0\xdd\x8c\x44\xc3\x3d\x4c\xd4\xa1\x21\xa9\x96\x00\xaa\x94\xc6\x73\x88\x66\xb5\xaf\x3e\x9c\xfb\x70\xe2\x83\x1c\xdd\x22\xaf\xe1\x3c\x0a\x7d\x91\x5c\x8a\x34\x1e\xba\xe1\x7d\x27\xb4\x63\x35\x8d\x6e\x70\xa1\x2e\x7c\x16\xb0\x0b\x11\xdd\x57\xd3\xf0\x52\x78\x73\x23\xff\x42\x61\xaf\x43\x26\x3a\xf0\x6b\xdd\xe4\x52\xc4\xc3\x3f\x83\x24\xbc\xb8\xf0\x84\x94\x14\x07\xbe\x53\xdc\xf4\x30\xb6\xb1\x74\x42\xf7\xf9\xe0\x41\x6f\x9e\x0c\xb6\x7a\x73\x05\x98\xd2\xc8\x74\xc2\xc3\x24\x09\x7d\x03\x8c\xf1\xfc\xa6\x17\x87\x9e\xeb\xf4\xa2\x0b\xce\xc8\x08\x7a\xea\xff\xe1\x78\xf3\x01\xad\xc1\xd2\xd5\x36\x89\xa5\x28\x8f\xa5\xd1\x94\x5d\xe1\x11\x43\xdc\x01\xb4\x90\x37\x34\xb2\xda\x20\xac\x4a\x96\xfa\x69\x5c\x08\x5f\xd4\xe6\xa1\xe4\xcb\x53\xb4\xa0\x1f\xfa\x94\xb6\xa9\x09\x15\x55\x96\x34\xd7\x14\x8e\x57\x2c\x04\x4b\x9b\xa2\x1b\x78\x6e\x50\x0b\x93\xf9\x15\xf4\xe2\xa5\x8c\x61\x0d\x7d\xac\xe6\xce\x50\xfa\x4c\x90\xba\x6b\x66\x94\xc3\xd9\x7a\xc3\x54\x83\xa1\xea\x93\x1b\xe6\xa0\xad\x15\x8c\x6d\x44\x0e\x2c\xc0\xc0\x74\xee\x9a\x68\x35\x88\x00\xf6\xa4\xe8\x6a\x9f\x2e\xef\xdf\x7a\x22\x25\x81\x94\x4c\x7a\xd7\x27\x35\x04\xdb\xef\x1d\x46\xe3\x71\x61\x35\x7e\xd5\x55\xa1\xc0\x32\xfe\xdc\x55\xa1\xc0\xac\x79\xd9\x4a\xfb\x41\xe9\xdb\x00\xef\x7d\x6b\x1a\x11\x23\xc2\x6c\x21\xdf\x3a\x87\x6b\x97\xbc\xf4\xc1\xc0\xa5\xac\x73\x4c\x06\x14\xde\xfb\xc4\x88\x93\x85\x27\xe2\x4b\x21\x54\xf0\x47\x90\x81\xe1\x85\xcc\x51\x08\x0d\x24\x65\x78\x86\x51\x94\x88\x28\x0a\x35\x78\x03\xf9\x94\x12\xe3\x39\x73\x3d\xe1\xf4\x92\xb0\x27\x9f\xe9\xed\x1e\x1f\xf7\xa6\x51\xe8\x9b\x08\xf4\x4b\x35\x82\x68\x4e\xe1\x4d\xed\x2b\xda\xa6\x90\x04\x56\x34\xb4\x9f\x37\x76\xc9\x6f\x3e\x04\x1b\x86\xe7\xf2\xfb\x3c\x0c\x93\x38\x89\xd8\x7c\xb0\x3d\x1c\x0d\x47\x03\xe6\xcd\x2f\xd9\xf0\xe1\xc0\x71\xe3\xe4\xbe\x1d\xc7\x55\x85\xa1\xef\x06\x43\x5b\x6a\xbe\xdf\x7d\xd9\xe7\xaa\x0d\x14\x83\xd8\xb5\x88\x43\x5f\x0c\xb6\x87\x8f\x86\x23\x7c\xb2\x7e\xbb\x7a\xf8\xf3\xd2\xc3\xc2\xf3\x07\x0e\x4b\x74\x90\x2d\x3e\xd8\xbc\xa5\x1e\x7b\xe5\x2b\xb1\x6e\x05\x1f\x64\x47\xf2\xc8\x27\x10\x0d\xed\x4c\xfe\xe3\xd1\xa7\x55\x26\xd7\xa8\xbc\x4a\x8a\xab\x72\xe1\xb2\x9a\x98\x53\x19\x12\xdb\x6e\xda\xab\xde\xfa\xd5\x58\xee\xf9\x24\xba\x3b\x7d\x17\x42\x60\xb1\x4f\xf1\x48\xb0\xab\x5e\x54\xb2\x09\xf5\x3b\xc9\x1b\xc5\x41\x59\xac\x9d\xdb\x55\x97\x8a\x67\x97\x9e\x29\x7b\x78\xa6\x0c\xf6\xac\x7e\x52\x53\x36\xc0\xcb\x06\x82\xa7\x6b\x5b\x6d\x3a\xc0\x2f\x37\x6e\xd7\xe0\x73\xcb\x9b\x88\x42\x4f\x6a\x41\x8f\xf0\xcc\xb7\xdc\x94\xfc\xb0\x77\xcc\x23\x0f\xec\xb7\xe6\xae\x07\xf6\x91\xb9\x26\x0c\xb2\x3f\x91\xeb\x14\xc1\x29\x87\x2c\x37\x95\x2c\x8f\x58\x5b\x9b\xc0\xcc\x5d\x72\xee\x81\xf1\x37\x3c\x44\x7d\x00\xea\xd7\x44\xfe\xb2\xdf\x23\x14\xea\x07\x0f\xa2\x21\x8f\xe1\x5c\x92\xc6\xf5\xa4\xca\xfd\x6b\x56\x09\x81\xa3\x21\xe7\x14\x73\x19\x25\x88\x78\x93\x83\x3d\x32\xbd\x84\x7c\xf5\x28\xd8\x0f\xcc\x17\x31\xd8\x8f\xcc\x16\xf6\xc1\x1f\x9b\x87\xe4\x1f\x6f\x14\xab\xc2\xc3\x80\xc6\xc6\x92\xe7\x39\x7d\x9a\xa6\xd6\x8f\x37\xcc\x0d\xcc\x1f\x6e\xe0\x26\xe6\x33\x9f\x1c\xd8\x94\x8c\x68\x9e\x43\x30\xdc\xf7\xfc\x49\xd1\x6e\x2f\xc0\x0c\x5d\x08\x49\x85\x27\x88\x3d\x37\xe8\x25\x14\xff\x44\x13\x4c\x15\x66\x58\x96\x98\x64\xe4\x21\x35\x03\x12\xfd\x43\x7c\x81\xe4\x1f\xe2\x0b\x35\xe5\xa5\x25\x2f\xa5\x44\xbd\xef\xf9\x90\xa6\xd4\xc4\x2b\x2b\x4d\x73\x92\x5c\xba\x31\x7d\xfa\xff\x05\x00\x00\xff\xff\x4d\x56\x37\xf0\x34\xad\x01\x00"), + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xdc\xbd\x8b\x76\xdb\xba\x92\x28\xf8\x2b\x32\xdb\xad\x03\x6c\x95\x18\xca\xaf\x24\x94\x71\x34\x4e\xe2\xbc\x76\x62\x27\xb1\xf3\xf4\xf6\xcd\x05\x29\x48\xa2\x2d\x81\x0a\x08\x5a\x76\x2c\xf5\x6f\xcc\x07\xcd\x8f\xcd\x02\xc0\x07\x48\x3d\x92\xdd\x7d\xfa\xde\x3b\x73\xce\x5e\x0e\x45\x16\x0a\x05\xa0\x50\xa8\x2a\x14\x0a\x5b\x83\x94\x87\x32\x8a\x39\xe2\xf8\xde\x49\x13\xd6\x48\xa4\x88\x42\xe9\x74\xf3\x0f\x0d\x81\x38\x08\x90\xf8\x5e\x30\x99\x0a\xde\x90\x2e\x25\x1c\xa4\x3b\x20\x02\xe4\xa2\x00\x1b\xa3\x12\x44\xa0\x1d\x90\x50\xa0\x16\xc5\x07\xbb\xb6\x1c\x1d\x12\xc0\xf1\x62\x81\x4b\x54\x7d\xc4\x2c\x54\xbb\xc0\x4a\x54\x72\x19\xd5\x46\xec\x0c\x49\x30\xf8\xed\x0a\x24\x4a\xad\x0a\xf6\x20\x2d\x2b\x60\xcb\xd8\xfe\x6e\x9d\x29\x62\x50\xd4\x6a\x57\x1b\x22\x6a\x55\xbb\x0f\xb4\xac\x36\x5d\x46\xf8\x2f\xa0\x84\xa2\x14\x6c\x5a\x6c\x62\x18\x0a\x2d\x62\x0e\x20\x2c\x89\xa1\xcb\x38\xff\x7b\xe8\x0b\x11\x85\x1a\x85\x36\x89\x29\x8a\x2d\x12\x1f\x42\x5c\x92\x18\x2e\xa3\xfd\x5f\x46\x75\x8c\x42\x58\xa6\xdb\x26\x9c\xa2\xc8\x22\xfc\x11\x44\x25\xe1\xf1\x32\xe6\xff\x9d\x6d\x89\x50\x0c\x2b\x5b\x63\x37\x27\x46\x03\xab\x39\x8f\x61\x50\x36\x27\x5a\x46\xfe\x7f\x58\x0b\x07\x28\x82\x75\x6d\xb4\x1b\x39\xab\x89\xb9\x1d\x42\x08\x77\x69\x8f\xbb\x03\xa4\xde\xfb\xaa\x1e\x24\xad\x12\x77\xa6\x04\x94\x44\xee\x56\xcb\x00\x2b\x4a\x21\x66\x15\xbc\xcd\x0b\x42\xd9\xe4\xbd\x7a\x51\x48\xed\xc2\x28\xb5\xca\x27\x65\x79\x28\xfb\x71\x7f\x19\x03\xd0\x1a\x0e\x44\x2d\x34\x03\x1b\x0d\x94\x63\x74\xb0\x0a\x11\x84\xcb\xa8\x50\x68\x61\x0b\xaa\xd8\xa0\x64\x83\x87\xab\xf1\x41\xbc\x12\x23\x8a\xf1\xe2\x86\x8a\x46\x44\xfa\xa8\x1c\x4e\x33\x34\x83\x58\x20\xf5\x8d\x91\x23\x21\xe8\x1d\xe2\x18\x52\xe2\x75\xd3\x43\xde\x4d\x5b\x2d\xcc\x2e\xd2\x4b\x22\x91\x68\xa5\xb8\x9b\xcb\xff\x05\x86\x1b\x32\xae\x60\x2a\xf1\xc8\x12\x0f\x23\x5e\x97\x1d\xf2\x66\x53\xb8\x41\x97\xb5\x5a\x58\x5e\xb0\x4b\x22\x5c\x0a\x82\xa8\x57\xc5\xe2\x37\x66\x7c\x28\x47\x84\xc1\xa9\x5a\x5a\xf0\x02\xc3\x36\x41\xf5\x0a\xf2\xc9\x72\xc1\x2f\x17\x18\x36\x35\x24\x47\x08\x69\x46\x0b\xc3\x40\x89\xd7\xa5\x87\xac\x4b\x5b\x2d\x9c\x5e\xd0\x4b\x22\x2f\xe8\x65\x4e\x41\x7a\xc1\x2f\x89\x80\x74\x81\x61\x7d\xb3\x44\x8e\x35\xef\x29\xd9\xea\xe4\x7d\x25\xcb\xbe\x12\x17\x69\x81\x97\x5d\xc8\x4b\xc2\x81\xfd\x3e\xbd\x0a\x19\xd3\xc8\x04\x51\xb3\x47\x5e\xa4\x97\x20\x8a\xae\x17\xbf\x89\xa9\xdd\xe9\x7a\x87\x84\x75\x59\xbb\x5d\x20\x62\x35\x44\xb8\xfb\x77\xda\xba\xa2\xa5\x1c\xa9\xb6\x56\xd8\xe2\xbf\x3c\x2a\x5a\x62\xb4\x28\xa8\xd1\x29\x30\xa7\x2b\x31\x17\xdc\x93\x8c\xa3\x90\xe9\x16\xfc\x82\x02\x51\x52\xc0\xdb\x0c\x68\x4e\x47\x0b\xa5\x05\x75\x87\x69\x2f\x7f\xf4\x53\x8c\x21\x24\x5e\x37\x3c\x64\xdd\xb0\xd5\xc2\xf4\x22\x54\xe3\x1b\x5e\x76\x15\x4e\xf3\x25\xcd\xbf\xb4\x98\xe2\xa9\xb0\x18\x7b\xba\x82\x99\xac\x51\x5c\xf3\x29\x8c\x79\x12\x8f\x99\x3b\x8e\x87\x88\xb7\x1c\xbf\xe1\xb4\x26\x08\x63\x10\x0b\x5c\x6a\x8f\x13\x94\xc3\x3b\x87\x11\x97\x4c\x70\x3a\x4e\xfe\xe9\x94\x72\x63\xa4\x64\xb5\x1c\x89\x78\xd6\x38\x16\x22\x16\xc8\x19\x49\x39\x4d\xfc\x07\x0f\x86\x91\x1c\xa5\x81\x1b\xc6\x93\x07\x6c\x3c\x79\x10\xc6\x82\x3d\x08\xc6\x71\xf0\xa0\xe3\x7a\xae\xf7\x60\x14\x71\x99\x3c\x70\x5a\xbc\xe5\xb8\x93\xbe\x63\x89\xa2\x61\x8d\x45\x80\x91\x8b\x4b\x48\xc9\x54\x77\xb3\x07\x0c\x77\xd3\x66\x13\x49\xc2\xdc\x69\x3c\x45\x18\x77\xd5\x37\xe9\x52\x90\x6e\xa0\xbf\x5b\xc3\x59\x60\x9d\x96\xe2\x3e\x1a\xa0\x8e\xe7\x1d\x4a\x9c\xb3\x93\x3b\x4d\x93\x11\x3a\xd5\xf5\x62\xd8\xf2\xba\xd1\x00\x71\x42\x88\xc8\x20\xcc\x1b\x27\x0e\xae\x58\x28\x9d\x2d\x22\xef\xa6\x2c\x1e\x34\xf8\x7c\xce\xd3\xf1\x58\xc9\xc7\xe2\x29\x2f\xe2\xe4\x15\x3b\xa4\x00\x6f\x36\x47\x68\x1f\xc3\x56\xa7\x9b\xb7\x2d\x6d\x44\xbc\xc1\xdd\xed\x43\xaf\xd9\x44\x9c\x0c\xa4\x92\x65\x42\xfd\xab\x08\xe1\x38\x1a\xa0\xad\x29\xe2\x7a\x66\xaa\x3f\xb2\xd5\x51\xcd\xcb\xa8\xea\x74\x73\xf2\xb4\xc8\x3d\x26\x63\x34\xc4\x70\x4d\x56\x0f\xf8\xd6\x30\x63\xdc\x72\x74\x8f\x72\xc6\x5d\xd9\xba\xbc\x7b\x74\x4f\xf4\x3c\x9f\x1f\x8a\x5e\xbb\xe3\x77\x54\x5f\x6c\x71\x77\x3b\xfb\x8e\x24\x39\x42\x5c\x49\x5a\x97\x62\x3c\x9f\x67\xbf\x03\x10\x6e\x80\x71\x4f\xfa\xea\x57\x08\xc2\x0d\xb1\x6e\x77\x97\xbb\x81\x96\xd3\xcd\xe6\x56\xb5\x6c\x97\x13\x5d\x4e\x49\xec\x62\x08\xe5\x7c\xae\xb0\xf5\x3a\xbe\x70\x03\x55\xbf\x67\x16\x98\xb3\x35\xcd\x34\x8d\xc2\x87\xde\x02\xc3\xd5\x5a\xd1\x9e\x01\x75\xd6\x4f\x0f\xef\xf0\x28\x9f\xe8\x6b\x21\x48\x0e\x82\xe1\xe9\x32\x39\xd9\xd7\x42\x0e\x1e\x7a\xbd\xbe\xf4\x45\x6f\x2c\xfd\x44\x2e\x30\xbc\x22\x5e\x39\x14\xa7\x36\xea\x7b\xea\x73\x08\x7c\xb1\x28\xd9\xf7\x7b\x55\x16\xe5\x10\x10\xfa\xd2\x82\xfa\x60\xb0\xe4\xd3\xe6\x7e\xa1\x7b\x5c\x6a\x2e\xc3\x66\x89\xb8\x90\x97\xe5\x4b\x61\x5e\x0a\xf5\xb2\x90\xad\xaa\xf4\x17\x32\x46\xe7\x16\xa7\x9c\x1b\xc4\x8a\x4f\x94\x85\xc9\x87\x16\x5b\x17\x7c\xd2\x12\x19\x6b\x04\xf9\x2b\xd1\x35\x42\xfe\xa3\x19\xe4\x6c\x84\xbb\x96\xa4\x56\xdc\x60\xde\x62\x46\x98\x1b\x94\xa0\xf9\xf8\x6b\x7a\x4e\xc8\xfd\xb6\xef\x2d\x4a\x82\x3e\x56\xfa\x6b\xdb\xef\x40\xd1\x67\x0a\xfe\x0d\x19\xa3\x8f\x16\xfd\xcf\x94\x98\xca\xab\x15\xe4\x04\x24\xe1\x99\xec\xed\xca\x76\xbb\x8b\x85\xaa\xf8\x42\x56\x17\xae\xa2\xf8\xe7\x6a\xf1\x8b\x4b\x8b\x6c\x61\xa4\x07\x77\xa9\x55\x52\xc1\xfd\xdc\xa8\x02\x5d\x5c\x76\xf5\x1c\x90\x4a\x3b\x51\x1c\x0f\x92\x48\xd5\x0b\x06\x9d\x5e\x9d\xb4\x48\xa3\xa5\x38\x7b\xa6\xf4\x50\x0c\xaf\x09\x92\x35\xcc\x4a\xac\x15\x42\xc5\xc6\xdd\x6c\xb2\x6a\x05\xa0\xbb\x19\xa7\xa6\x9a\xbb\xb2\x1a\x60\xd5\xaa\x52\x55\x55\xb8\x54\x8f\x52\x7a\xf3\x9a\xe8\x52\x4d\xcd\x66\xba\xaa\x3a\x48\x49\xea\x06\x98\x9a\x4a\x6f\xab\x95\x42\x5a\xad\x98\xaa\x8a\xd9\x8a\x8a\x95\xb6\x9c\x57\x1d\xae\xae\xba\xd9\xa4\xeb\xeb\x07\x4a\xa8\x1b\xe0\xd0\x50\x91\x2c\x53\x01\xb4\x4a\x49\x58\x9b\xfd\x12\x4a\xc3\xe4\x19\x52\x4c\xe1\x26\xb1\x90\xeb\x44\x8c\x96\xe6\x5a\x94\x2f\xf4\x7f\xf0\xad\x22\x8f\x7e\x13\x1b\x99\x29\x48\x9b\x2f\x09\x21\x89\xec\x79\xbe\x7a\xe8\x4b\x2d\x93\x75\x05\xeb\x04\x15\x6f\x29\x1d\x0c\x5e\xae\x95\x86\xbc\xbd\x41\x4f\xe0\x7f\xe8\xd2\xef\xd7\x97\x7e\xb0\xa9\xf4\x03\x31\xf7\xf4\xe7\xb7\x54\x8e\xdc\x69\x3c\x5b\xaf\xab\xfc\x3b\x5f\x85\xe7\xdf\x09\xcf\x5b\xee\xa9\xa5\xb6\x37\x42\x9d\x0e\xf6\xbd\x43\xd1\x6c\xf2\x43\x6f\x3e\x17\x6a\xf5\xf4\x0e\x79\x4f\xb4\xb8\x9f\x69\x9b\xba\x32\x2a\x29\xdf\xc1\x5a\x04\xfd\x20\xfa\x4d\xc8\xa2\x31\xbc\x35\xcf\x83\x71\x1c\x0b\x78\x62\x7e\x88\x38\xe5\x7d\x78\x6e\x7e\x8c\xe3\x61\x77\x5d\x73\x9a\xcd\x4d\x8d\x9d\xcf\x37\x7d\xdd\x22\x44\x29\x57\x8a\x9e\x77\x64\xd3\x58\x75\xff\xd6\xc7\xdf\xd3\xa5\xcd\xaa\x40\x89\x70\xc3\x11\x15\x4f\xe3\x3e\x3b\x92\x28\xc5\x5d\x7a\xb8\xbf\xbf\xf3\xf8\x60\x3e\xdf\x3f\xd8\xed\x3c\x3e\xa4\x3d\x64\x6b\xdc\xa0\x54\x70\xdf\x7e\xd5\x12\x17\x69\xab\xa3\xbf\x90\x1d\xbc\x28\x54\xa8\xab\x38\xe2\xc8\x71\xf0\x46\xc3\xe6\xe2\x12\x2a\xba\xb1\xb1\x41\x0a\xd2\x94\x8a\x13\x2e\x51\x98\xb6\x5a\x10\x56\xa9\x0c\xe7\x73\x44\x5b\xa6\x80\xa2\x10\x38\xa2\x58\x89\x02\x3d\xb3\x69\x41\x96\xb4\xc8\xea\xfe\x2d\xbb\x28\xa7\x49\x1a\x9a\xe4\x6f\xd3\x24\x0b\x9a\x8c\x35\xa4\xd6\xb2\x45\xa9\x8d\xeb\xd1\x7f\x41\x7e\x87\x16\x65\x52\x65\x74\xa4\x44\x1b\x55\xb4\x4a\x07\xc3\x5d\x53\x47\x4a\xe8\x3f\xc9\xfe\xc1\xee\x8e\xd7\x6c\xee\x3f\xdc\xdd\xdb\xfd\x27\xa1\x3d\x79\xd1\x6e\xb3\xcb\x56\xea\xa7\x55\x0a\xe0\xd3\x3a\xde\x13\x6e\x32\x1d\x47\x4a\x6a\x2d\x30\x7c\x5d\x0f\xa5\xfb\x54\x03\xfd\x49\x7e\xd3\x58\xfa\x0d\xa6\x35\xeb\xf0\x7d\x66\x3f\xa9\xa5\x38\xad\xb2\x82\xc4\x5a\x2f\x47\x8c\xa4\xf5\xd6\xa6\x3d\x71\xd1\x6e\xcb\xcb\x16\xf3\x4b\xf5\xd8\x5b\xe4\x7a\x72\xd6\xed\x9c\x93\x7f\x19\x19\x5b\xbf\x4f\x47\x67\x51\x10\x84\x41\xf0\x75\xea\xf9\xd6\x7f\x08\x37\xe2\x7d\x76\x7b\x3a\x30\x9d\x2b\xd7\x81\x2a\x39\x58\x83\x65\x6b\x61\x73\x35\xe7\xb0\x68\xa1\x52\xbe\xc7\x34\x91\xaf\x0a\x04\xa4\xf8\xd6\xce\xc1\x17\x18\xd2\x65\x9c\xa6\xab\x0a\xcd\x29\x1a\x20\x79\xd8\xc9\x95\xbd\x13\x4b\xaf\xf3\x40\x6b\x21\xed\xce\x21\x62\x36\xad\xda\x38\xcb\x95\x0f\x86\x81\xb5\x88\xac\xaa\x1c\x7a\xa4\xe8\xba\xe6\x28\x4d\xcf\x83\x7e\xae\xea\xad\x93\x94\x0a\xac\x03\xac\x04\x2b\x9d\xf8\x4b\x70\xbb\x30\xf0\x39\x0c\x73\xcd\x31\xde\x54\xf5\x9e\xd6\xb9\x47\x3e\x5f\x64\x84\x0e\xd6\xf6\xbb\xae\xe8\x42\x5c\xaa\xd1\x09\xf8\xfa\x79\x92\xc1\x81\xd4\x90\x09\x5f\xad\xdb\xd5\x81\x81\x5d\xae\x57\xcf\x96\x81\x21\xbd\xdc\xa4\x54\xad\x2a\x00\x54\x17\x49\x57\x16\xb1\xdc\x8d\xb5\x42\x10\xea\x62\x74\x4d\x31\xcb\xaf\xb8\x54\x10\x62\x5d\x34\x5e\x5b\x14\xa2\x4d\x85\x21\xba\x5c\xb5\xf8\x48\x71\x97\x17\xea\xab\x57\xaf\xcf\x4e\x4f\xdc\x29\x15\x09\xd3\x8a\x59\x48\x65\x38\xb2\xfc\xcd\xdb\x12\xcd\xd0\x44\x82\x73\x3e\x8a\x92\x46\x94\x34\x78\x2c\x1b\x37\x74\x1c\xf5\x1b\xaa\xe4\x56\xc3\x69\x71\x77\xc2\x92\x84\x0e\x19\x28\x04\x4a\x37\x1a\x2b\x2e\xe8\x73\x8b\xcd\xfa\x59\xed\xc9\x2c\xd2\xf8\xdd\x6d\x7c\x1f\xd2\x84\x35\x76\xfd\xcc\x3f\x10\xc4\xf1\x98\x51\xcb\x3d\x20\x7a\x53\xa5\x2b\xfa\x13\x8e\x1c\xda\x78\x72\x7a\xfa\xc6\x51\x4a\x9f\x2e\xb5\x93\x97\xe2\xe9\x24\x60\xa2\x34\xd2\x45\x4f\x83\xf3\xc6\xab\x93\x73\x05\xee\x23\x71\x48\xda\x3b\x9d\xbd\x87\x7b\x8f\x76\x0f\xf6\x1e\xce\xe7\xe5\xf3\x21\x11\xf3\x39\xf2\xe6\x02\x2b\x45\x04\x37\x9b\x68\x2b\x4a\x9e\x47\x3c\x92\xaa\x2b\xe6\x73\xf1\xef\x1d\x5c\x47\xa7\x49\x32\x34\xec\xd5\x68\x58\x43\xf8\xf3\x37\xa7\x47\xe7\x25\xe5\x07\x79\xa9\xba\xd9\x98\x97\x12\x8d\x88\x27\x92\xf2\x50\xbd\x3c\xd3\x40\xfa\x4b\xcb\x71\x72\x94\x67\xe7\x1f\x5e\x9d\xbc\x28\x71\x3e\xf6\x73\xd9\x96\xf9\x5c\x54\x01\xee\x86\x06\x5e\xbd\x2c\x61\xf7\x73\x58\xab\x25\x0f\xf3\x77\x5a\x49\x72\xa3\xc4\x28\x4b\x02\xf7\x6e\xb8\xf1\x5c\xc0\xb3\xbc\xee\x37\xaf\xce\xac\xd6\x3c\xfa\x75\xc9\x6d\x9e\x15\xe5\x8d\xa3\x0f\x1f\x8e\xbe\x96\x85\x3b\x9e\x9f\xcb\xcf\xfe\x4a\x7f\x92\x28\xbd\x48\xf3\xf9\x56\x6e\xa1\xe7\xe2\x35\x43\x7a\xfa\xe4\xf5\xf1\xd3\xf3\xc6\x2c\x92\xa3\x06\x6d\x0c\x22\x36\xee\x37\x38\x9d\xb0\x7e\xe3\x7f\x3a\x2d\xd9\x72\xfe\xa7\xae\xd0\x48\xe1\x7e\x46\xd4\x85\x2c\x3d\x9c\x31\x43\x0c\xf7\x98\xaf\x19\x7d\x24\xd5\x0c\xd2\x46\x8f\x21\xb1\xe3\x2b\xf2\x98\x5e\xe1\xea\x6d\xac\x11\x52\xb6\x2e\x1a\x20\x51\xac\x32\xb2\x02\xd6\x78\x73\x7a\xf2\xe2\xf8\x43\x83\x6a\x5c\x8d\x13\xc6\xfa\x0d\xbd\x18\x34\x34\xb1\x8d\x20\x95\x8d\x98\x8f\xef\x1a\x09\x63\x0d\xa7\x95\xa3\x69\x39\x0d\xc6\xa5\x88\x58\xa2\x2b\xf8\x8d\x96\x0c\xeb\x2d\xd9\xf1\x7f\xd9\xc5\xbf\x68\xa0\xe9\xe9\xa2\x3b\x53\xa0\xc4\x2c\x71\xa9\x19\x18\xdd\xec\x11\x4d\x4e\x67\xfc\x9d\x88\xa7\x4c\xc8\x3b\x94\x62\x7c\x6f\x51\x9b\x5e\x1a\x65\x41\x93\x8a\x6d\x11\x33\x92\x90\x66\xf4\x52\xf2\x11\x9d\x22\xf3\x0b\x4a\xdd\x75\x2a\xd1\x47\x89\xca\x06\xed\xfa\xa5\xed\xcb\xdd\x01\xc4\x84\xbb\x43\x88\x88\xd7\x8d\x0e\xe3\x62\x45\x6e\xb5\x32\x02\xe2\x8b\xe8\x32\x1b\x9c\x6a\xf5\xac\x1b\x92\x10\xa9\xca\xac\x9a\xc2\xbc\x96\x3d\xbf\x24\xbf\xd6\xd3\xfa\xf5\x48\x97\x54\xa2\x81\x65\x25\xf6\x0b\xba\x06\xe4\x04\x02\x45\x55\x37\x70\x83\x6e\x40\x02\x37\xc8\x88\x09\x8c\x4b\x27\x1a\xa0\x1a\x29\x03\xf2\x51\x21\x84\x41\x41\x8c\xea\x1d\xdd\xf2\x01\x2e\x9a\xee\xd7\x84\xb3\xf1\x10\x65\x5f\x3d\x6b\x86\x73\xd5\xaa\xd2\x6d\x73\xb3\xd9\x33\xbf\x72\x6f\xe0\xde\xf4\xb0\x11\xe0\x7a\x6b\x20\xeb\xc1\xb0\x3a\x80\x43\xa9\x96\x1d\x3d\x80\x7a\x3b\x21\x74\xa9\xd5\x9f\xca\x48\xb0\x5c\xda\xdb\xf6\x2e\xe7\x0c\x85\x0c\x0a\x32\x56\xec\x79\x9a\x7d\xa7\xb2\xf4\xa4\xaa\x59\x14\x4b\xd4\xf1\xed\x94\x85\x32\xe2\x43\xb5\x28\xe9\xc5\xa8\x74\xcb\xf3\xc2\x61\xb7\xec\xc8\xe6\xee\xb6\x5a\x01\x0a\x0f\xee\x56\xa7\xbb\xb4\x4e\x79\x7e\xb5\xeb\xb9\x4b\x15\x1e\x97\x76\xb3\x65\x2c\x5b\x97\xb2\xa5\x21\x93\xf5\x15\x91\xbb\xe5\xd5\xc5\xb5\x1b\x6a\x1c\x61\x2e\x86\x33\x99\x9a\x4f\xd8\x0c\x6c\xc4\x0b\xf7\x71\x21\x38\x0b\x0c\x7d\x8d\xa1\xdf\x6c\x2e\x43\x59\xb4\x32\x0d\xc5\x56\x41\xed\x96\x50\x03\x0d\x35\x68\x36\x87\x0a\x6a\x08\xc2\x1d\x96\xd3\xa0\x80\x1a\x69\xa8\xd1\x2a\x5c\xc5\xe2\x62\x21\xb0\xd8\x6f\xb8\x5e\x6b\xde\x2a\x55\xee\x72\x10\x2c\xf5\xb9\xcb\x0e\xa5\xde\xc7\x54\xcc\xa7\x2a\xd6\x7b\x6a\x17\xec\x72\x9d\xf3\x7f\xba\x56\x11\xd5\x0a\x8f\x59\x7d\xa3\xc1\x1d\x12\xa0\x04\x20\x70\xdc\x72\x1c\x5b\x31\x9e\xd9\x1c\xc8\x35\xce\xbb\x0d\x6a\xab\x34\xfb\x98\x32\xd3\x83\x6f\x39\x51\x68\x4b\x74\xc7\x16\xba\xfb\x6d\xdf\x03\xaa\x94\xe6\xe2\xf3\x75\xf5\x73\xa7\xf6\xf9\xa8\xfa\x79\x07\x02\x9f\x43\xe8\xab\x2a\x8c\x96\x7e\xb6\x41\x4b\xdf\xd5\xd0\x7d\xad\xf8\xc3\xd5\x06\xc0\x3d\x0b\x50\xb7\xe2\x29\xb7\x5d\xf2\xaf\x34\x11\x5c\x7b\x9e\x81\xf9\x4f\x79\xab\x95\x99\x0a\xba\x07\x47\xfe\xc5\xe5\x22\x97\x90\x27\x0a\x16\x78\xd9\x82\x53\x7b\xc6\x1f\x71\x64\x4f\x73\x8e\x8e\x39\x7a\xa5\x00\x30\xb6\xe7\xf9\xf7\x8c\x40\xee\x8e\x8c\x81\x24\x30\x68\xc4\xba\xc9\x1f\x2a\x2d\xb1\xc7\xa2\x86\xfe\xbb\xf9\x0a\xa6\x1a\x5d\x85\x69\xde\x17\x4e\xb6\x3a\x70\xce\x95\x65\x56\x54\xaa\x2b\x50\x72\xe2\x9c\x67\x8e\x6c\x0c\x5b\x5f\x32\x77\xb7\x2a\xe1\x75\x39\x39\xe7\x6e\x32\x8a\x06\x12\xe1\x2e\xde\xb2\x03\x37\xf4\x86\x8e\x70\x07\x99\xc5\xcc\xd5\x7c\x72\xb7\x15\x8b\x7b\x66\x5b\xac\xa3\xfe\x29\xe0\x86\xca\xf6\x1c\x6a\xf1\xc3\xbb\x58\xb8\x43\xa2\x7e\x46\x5a\xc4\xaa\xc9\x63\x1a\xa4\x10\xea\x0f\x01\x52\xe8\xd4\x72\x93\x43\x2e\xd8\x38\x61\x8a\x5a\x1d\xdf\x51\x6c\x33\xb8\x03\x37\xd4\x55\x07\x95\x9e\x50\x78\xb8\xea\x42\xed\x82\x88\x06\x68\xdf\x50\x93\x91\x27\xdc\x51\x75\x0e\x66\x15\x0f\x74\xc5\xa3\xbc\xc9\x58\x57\xda\x50\x34\x28\xee\xd2\x3e\x48\xcf\xef\x28\x53\x50\x81\x42\xe4\x0b\x77\xb8\x80\xbc\x6c\x7f\xb1\x58\x20\x8e\xbb\xba\xb7\x17\x8b\x0d\xd6\xdc\x47\x35\x50\x0c\xb8\x1b\x1e\xa9\x3f\xfb\xea\x8f\x57\x2e\x08\xcb\x61\x31\xf8\x7e\xb1\xa8\x6c\xe0\x7d\xac\x19\x72\x66\xed\x9a\xa1\x31\x07\x0e\xa2\x27\xdc\xc1\x98\x0e\x13\xff\x26\x8e\xfa\x0d\x0f\x77\xf5\x2a\x36\x9f\x8f\x50\xe6\x15\x8d\xc9\xfd\x02\x22\x82\x42\x22\x91\x5e\xca\xd4\x4a\x4c\x28\x0a\x20\x52\x8b\xe2\x0a\xdb\x1f\x98\x96\x52\x4c\x69\x40\x6f\x78\xee\x9c\x7a\xa3\xc4\x53\x37\x75\x69\xb3\x89\x90\x24\x72\x3e\xbf\x5f\xe0\x0b\x76\x49\x52\x97\x22\x6d\x26\x81\x82\x58\x81\x90\x91\xfb\xa1\xb6\xa8\x0d\x89\x0b\x48\x09\x77\x43\xa0\x4a\x47\x06\xa5\xe7\x30\xad\xe7\x0c\x8a\xdd\x29\x77\x44\x5e\x71\x34\x43\x67\xbc\xe8\xa8\x86\x1d\x55\xa4\xbf\x70\xb8\xdf\xf6\xf7\x21\xf0\x6d\x66\x30\x5b\x37\xdc\xa5\x15\x6f\xb2\xbb\xdd\xbb\x43\x14\x98\x16\x6e\x7e\xd8\x6c\xc6\xbd\x5b\x1d\x76\x27\xdc\x08\x84\x7b\xa5\xde\xde\xe9\x17\x61\x4f\xb8\x6a\xa8\xd5\x2b\x35\x0c\xc0\xdd\x00\xe3\x05\xb2\xdd\x6b\x72\x81\x62\x08\xac\x01\x0a\x4c\x53\xd5\x98\x30\xe0\xaa\x5b\x07\x28\x52\xba\x02\x08\x0c\xdf\x38\x8a\x21\x74\x03\x48\x51\x84\x0b\x1c\xd5\xb7\x40\x7b\xf7\xd3\x58\xc8\xc4\xa7\x0b\xff\x3e\xdb\xdc\xe2\xe4\x7e\xa1\x07\xf0\xd9\xef\xca\x04\xe1\x0e\x51\x5d\x24\xac\x59\x2f\x66\xe8\x03\x07\xee\x8e\x20\x13\xdb\xa2\xca\x72\x9f\x37\x07\x6c\x69\x61\x7e\xed\x0b\x18\x2b\x81\x5e\xca\xb6\x9f\x75\x89\x3e\x51\xdf\x55\x1b\x5e\x6f\x14\xe5\xdc\xe7\x10\xd7\x7c\x38\xdf\x8a\xc5\x48\xb3\x10\xa4\xf9\x46\xa7\x66\xcb\x97\x1c\x6d\x79\x20\x20\xd5\x0b\x1d\x06\xf5\xbb\x03\xb2\xf8\xcd\xf1\xf7\x6c\x3d\xbd\xdf\xf6\x9d\xc1\xad\x03\xd4\x4f\x2f\xd8\xe5\x7c\x7e\x1f\xf9\x27\x70\xe5\x9f\x54\x02\xcb\x5e\x5a\xf3\x36\xd3\x92\x44\xa1\x25\x75\x7c\x33\x01\x84\x7b\x0d\x94\x20\x4a\x52\x88\x09\x83\x19\xe2\xbd\x37\xfc\x82\x5e\xba\xcc\x37\xff\x0e\x2a\x7a\x5e\xb9\x93\x18\x77\x85\xde\xad\xfa\x81\x95\xe8\x9c\x2a\xb9\x51\x2c\xc1\x4a\x47\x2c\x77\xa3\xd4\x04\x41\xf2\x22\xbd\x54\xd5\x50\x48\x09\x4a\xb5\xaf\x19\x5b\x74\x03\xef\xa5\x6e\x44\x3e\x22\x0a\xa9\x1b\x61\x3f\x75\xaf\xb2\x1f\x57\x18\x52\x5c\x38\x13\x4a\x43\x42\xb8\x93\x6e\xe8\x06\xca\x24\x70\x03\xac\xdb\xaa\x98\x53\xb5\x36\xab\xb8\x5b\x71\x5b\x68\x32\xb2\x3e\x71\x63\x90\x70\x3f\xf5\x85\xcb\xe1\x87\xcf\x16\x66\x99\xa2\x10\x97\x9d\xf7\x5e\x37\xf7\x0d\xbf\xe0\x97\xcd\xe6\x08\xed\x5a\xfd\xfa\xa3\xca\x75\x1a\x12\x34\x24\xb9\x67\xfe\x5b\x0e\xc2\x17\x40\xfd\x27\x7c\x01\x9f\x8b\x35\xf0\xed\x5a\x2d\xa7\x12\xb5\xf2\xa4\x98\xf0\x12\x42\x72\x71\x09\x31\xd1\x98\x5d\xa1\xa4\x9d\x24\x1e\xd4\xa6\x87\x19\x8c\x84\xc9\xf3\x68\xc2\xe2\xd4\x92\xd9\xf9\x6a\x8d\xf1\x02\x64\x31\x18\xd6\xe7\x70\xcc\xa8\xc8\x8b\x09\xed\x0f\xca\xa1\x4c\x9d\x01\x89\x4c\xbb\xdc\x70\x8d\xdb\xbf\x2b\xf2\x3d\x4b\x5c\xaa\x80\x21\xa4\x24\x46\x42\xdb\x84\xc6\x3c\xc9\xf5\x47\xaa\xa3\xa2\xe8\x25\x2a\xe3\xe4\xa2\x05\x86\xfb\x24\x0d\x92\x50\x44\x01\xab\x88\xbd\x30\x5f\xd5\x17\x90\xf2\xd5\x20\x88\xab\x25\x20\xcc\x1c\xf6\x18\x5b\xae\x65\x7c\xe8\xcd\xe7\xa1\xde\x17\xd0\xbe\xfc\x0e\x5e\x98\x59\xfb\x9c\x77\xd7\x48\x9e\x55\x06\x8d\xde\x0a\xc5\xb9\x9a\xf5\x8e\x13\x27\xe5\x7d\x36\x88\x38\xeb\x97\xb6\x79\x3f\x0e\xd3\x09\xe3\xb2\x97\x3f\xf8\xf7\xd6\x86\xff\x8b\x42\x39\xa2\xd3\x29\xe3\xfd\xa7\xa3\x68\xdc\x57\x1d\xbe\x6a\x81\x65\x84\xb9\x3c\xee\xb3\x72\xd9\x98\x52\xc1\xb8\x3c\x89\xfb\xcc\x15\x6c\x3a\xa6\x21\x33\x08\x6e\x04\xe2\xf6\x92\xbb\xc0\xc0\x30\xdc\x57\xe4\xcd\xa7\x95\xba\xac\x6a\xc9\xd7\x0a\x3f\xda\x6e\xd1\x5f\xec\x81\x79\xd6\x98\xdf\xe7\x32\x84\x76\x59\x8b\xa4\x6e\x30\x9f\x7b\x90\x6d\x65\xa5\xe5\x0e\x5b\xab\xdc\xa4\xd2\x42\x36\xf4\x43\xe8\xfb\x63\xa1\xc3\x1f\x7d\x09\x03\x9f\x42\xe0\x33\xad\x21\xa0\x6c\xc5\x87\x3f\xff\x5b\x08\xfc\x3d\x12\x77\x7e\x8b\x44\xb3\x33\x23\x36\x69\xe9\x57\x3e\xd7\x4b\x4a\xe0\x77\x5a\x48\xe8\xca\x71\x65\x80\x84\xa8\x95\xd9\x57\xcb\x0f\x4c\x7c\x01\xd7\xb9\x66\xb1\x58\x27\x38\x04\xba\xe0\x20\x2e\x57\xe8\x5d\x46\x6f\xcc\x98\x56\x8a\xf5\xc6\x50\x86\x03\xe4\x2a\x2c\x79\x64\xf2\x42\x7b\xe0\x05\xd9\xa0\x10\x16\x78\x80\xad\xc2\x54\x46\x2c\x6b\x5c\xa9\x20\x68\xe3\x06\x80\x85\x0e\xd2\x55\x08\xed\x48\xe6\xc5\x6f\x6c\x10\x54\x10\x02\x5d\x85\xb2\x1a\xdc\xbc\xf8\xad\x2d\x84\x1a\x5a\x08\x57\x21\xae\x87\x3b\x2f\x7e\x73\x9b\x61\x09\x39\xc4\xab\xd0\x2f\xc7\x3f\x2f\x6a\x9b\x11\x03\x08\x20\x81\x31\xf4\xe1\x06\xb6\x61\x02\xa3\x4a\x15\x4b\x5f\x57\x55\x22\x48\x00\x92\x24\xc0\xc8\x18\x52\xd2\x07\x4a\x6e\x20\x24\xdb\x10\x93\x09\x44\x64\x04\x8f\x08\x21\x88\x93\x01\x5e\x15\x6e\x0d\xd1\xba\x80\x6b\x14\x65\xb3\xa8\xbe\x5d\xb2\x58\x1f\x14\xa2\x74\x1f\xea\x39\x96\x7e\x85\x81\x6e\x98\x85\x0e\xed\xd8\xc0\x10\x6e\x84\xdd\xa9\xc0\xc6\x1b\x61\x77\x6d\xd8\xee\xba\x39\xa6\x41\xf7\x14\xa8\x80\xd8\xbf\x1f\xe8\x12\x72\x51\x11\x03\x91\x28\xe5\xb4\xa3\xd6\xb9\xa9\x74\x94\xb1\xe6\x4c\x1d\x9f\xaf\x99\xff\xaa\x13\xb4\x29\xb8\xdd\x9b\xa1\x54\x80\x52\x66\x90\x24\x1c\x38\x49\x98\xde\xbb\x8c\xb1\x12\x66\xcc\xdd\x56\x62\xbf\x77\x87\x06\x0c\xf8\xe1\x6e\x2f\x10\x7e\x22\x20\x60\x4a\xad\x66\x2e\xc5\xfe\x0c\x45\x2c\xf3\x41\x2f\x30\xf6\xb3\xd0\x37\x60\xf9\x4e\xa1\x80\x60\x5d\x3f\x34\x4e\x11\x37\x4b\xbd\x12\xb7\x0b\x0c\xc9\xda\x1e\x0b\x5f\x29\x26\x70\xc3\x57\x18\xe8\x91\x2f\x5c\x7a\x04\x34\x55\xff\xa6\x95\xae\xd0\x32\xd7\xd2\x33\xef\x17\x56\xc4\x5a\xe1\x90\xa2\xc0\x88\x74\xb7\x21\x25\xd2\xe5\x3a\xba\x20\xee\xaa\xc1\xdb\x22\x84\xf5\x90\x24\x42\xab\xc5\x48\xfd\x43\xd4\xca\xa8\x06\x8b\x10\xc2\x9a\x4d\x27\x1c\xd3\x24\x51\x3f\xd2\x5e\x5f\x20\x69\x0e\x2b\x68\xf5\x94\x62\xdf\x7c\x3d\xa1\x13\x56\x40\x08\x03\x21\x34\xc4\x62\x39\xc2\xae\x2f\x2a\x3a\x3d\xe1\x17\xe2\xb2\xab\xfe\x10\xd6\x63\x2d\xa7\xe1\xb4\xa4\x6f\x1d\x57\xbb\x11\x55\xd7\xda\x76\x6e\xdd\x17\xdb\x0f\x0a\xc2\xbd\xd6\xc1\xa3\xd7\x84\xbb\x26\xb4\x19\xe7\x9e\x89\x02\xec\x1d\x77\x43\xc1\xa8\x64\xe7\xec\x56\xab\x07\x26\x90\x2f\x1a\xa0\x3d\x0d\x66\x79\x8e\xb9\x7b\xad\xcd\xd3\xab\xae\xfa\xc4\xdc\xed\x2e\x5e\xda\x5f\x48\x7b\x29\xb9\x48\x81\xb9\x57\x97\x7e\xbe\xcb\xad\x94\x6f\xa5\x90\x5c\x9b\xad\x6d\x72\x7f\xe5\xa7\x30\xf5\x45\xee\x3c\x42\x21\xb9\x11\x88\x81\xb2\xbf\xd9\x78\xf2\x9d\xdd\x30\x2e\xbf\x2b\xf5\xe5\xbb\x60\x03\x42\x21\x5c\x44\x03\xb4\x6b\x53\xbd\x2d\x90\x32\x8e\x47\x88\xbb\x43\x0c\x02\xb8\xdb\xc7\x10\x76\x8b\xcd\x81\x5e\xd1\xac\xe3\x31\x53\xaa\xd4\xc9\x19\xe2\xee\x00\xf4\x26\x59\xfd\x9b\xde\x3a\xeb\x3e\xe7\xcd\xa6\x43\xd5\x7c\x71\xc3\x66\x33\x74\x69\xbf\x7f\xac\x08\x79\x13\x25\x92\x71\x26\x90\x13\x8e\xa3\xf0\xda\x81\xe7\x1c\x85\x18\x83\x22\x21\xab\xb9\x70\x5c\xc6\xda\x60\x5f\xb1\x25\xf1\x82\xa3\x10\x6e\x04\xea\xa8\x46\xf4\xe2\x8b\xe8\xd2\x57\x7f\xf4\x26\x43\xa1\xc4\x86\x96\xbf\x5c\x2c\x39\xee\x95\x69\x27\xed\x68\x98\xae\x12\x49\x6a\x20\x7a\x2b\xfd\x14\x84\xbb\x89\xbc\x1b\xb3\x95\xc1\xae\x0b\xc4\x21\xc5\x7e\x36\xf9\xab\x18\x6c\xbb\x92\xab\x01\x79\x9e\x68\x2e\xd2\x4f\x6a\x1a\x94\xa6\xa6\x2c\xa3\x84\xd8\x25\x84\x44\x99\x91\x8a\x75\xa8\x76\x31\x85\xe6\xaf\xfb\xc3\xdd\x26\x84\x50\x6d\x34\xba\x3f\x08\xed\x86\x31\x97\x11\x4f\xd9\x82\xbb\x82\x4d\xe2\x1b\x56\xed\x68\xa6\x56\xb7\xb0\x74\x96\x44\xa0\xa6\xb2\x75\xec\x27\xb7\x57\x06\xee\x0f\x90\xa4\xaf\x45\x07\xf0\x7c\x7b\x45\x62\xab\xd7\x20\x25\x7a\xa3\x1b\x04\x91\x2e\x05\x4a\xd2\x5e\x7a\xb8\xdb\x13\x2e\xf5\x95\x10\xf1\x05\x48\xd2\x51\x53\x54\xb8\x81\xbf\x4b\x48\xda\x6c\x6a\x99\x12\x12\x24\x9b\x4d\xd5\x85\xf1\xf4\x9d\x88\xa7\x74\x48\xcd\x52\x06\x68\x67\x09\x3c\xc5\x0a\x74\x2a\x34\xe3\x3e\x63\x03\x9a\x8e\x25\xc2\x10\xe1\x2e\x23\xa1\x7b\xd5\x35\x71\xc3\xcb\x01\xf1\x0c\x53\xc2\x10\xc5\x5d\xed\x5f\x2b\x99\xa8\xb0\x74\xe2\x76\xbb\xab\x60\x2e\xe2\x4b\x05\xa6\x6c\x94\xe9\x22\x44\x54\x7b\x60\x72\xbd\xc0\xfd\x41\x38\x0c\x16\x48\x00\xc5\xc0\x97\xf9\x96\x41\x08\x03\xd1\x6c\xde\x4f\x69\x92\x44\x37\xcc\x4f\x54\x9d\x87\x3b\x4a\x33\x51\x82\x2d\x34\xee\xbd\xf5\x63\x61\xc0\x72\x35\x52\xb3\x88\xe6\x9d\xdd\x55\xdc\x57\xa8\xd1\x86\xe3\xac\x38\xa2\x2e\xeb\x71\x37\x61\xf2\x48\x4a\x11\x05\xa9\x64\xc8\x9c\x30\xcb\xea\xb5\x5e\xe3\x45\xc1\x9f\x7b\x7f\xaf\x0e\x48\x09\x73\x07\x5a\xda\xc4\x4b\xf5\x9d\x9c\xa1\x14\x56\xd7\x69\x3e\x95\xf5\xde\xd0\x71\xca\x0a\x51\x3f\x62\xe1\x35\xeb\x67\x3f\xb5\x23\x8f\x90\x54\xcd\x09\xed\xe2\xc3\x8b\x85\x14\x77\xf7\xb3\x88\xf7\xe3\xd9\x0a\xb1\x21\x1d\xb3\xe3\x70\xaa\x45\xa5\x6b\xcc\xbe\x62\xc3\xf4\x7e\x01\x4e\x36\x30\x0e\xdc\x0f\x99\xf4\x2d\xb5\x69\x20\xc8\x96\xa7\x54\x93\x32\x4c\xc3\xda\x15\xab\x2c\x01\x17\x45\x00\xfb\x30\x93\x1d\xe0\x61\xfb\x80\xf3\x48\xd8\xe6\xe1\xfd\xb6\x2f\x40\xf8\x12\x12\x9f\x81\xcc\x6c\x04\x48\x73\x63\xa1\x70\xc2\x94\x81\x4a\xd6\xb6\x8e\xa8\x1c\x25\xd1\x61\x9d\xb9\x60\xe2\x4a\x4d\x50\xda\x84\x9a\x8c\xe9\x16\x21\x46\x14\x74\xb6\x74\x8f\xed\xe8\x17\xb6\x27\x65\xa4\xd6\x4e\x0f\x98\xde\x6c\x25\xab\x7d\x44\x4a\xa6\xfe\xe6\x39\x29\xb5\xbc\x16\xa7\xdd\x32\x2b\x91\xbb\xca\x08\xe3\x6e\x1f\x98\xcf\x60\xe0\xab\x75\x20\xf0\xb9\x1b\x2c\x16\x4a\x30\x50\xd2\x59\x64\x7e\x2d\x9a\x79\xb5\xf6\x2b\x3b\xcd\x63\x88\x55\xe5\x10\x91\xb0\xd8\xb3\x24\x11\x21\xa4\x90\xf0\x83\x66\x33\x52\x33\x75\x40\xc2\x8b\x48\x31\x87\x92\xed\xaa\x03\x06\x76\x5b\x91\xd0\x0b\xf1\x35\xee\xaa\x07\xa1\x56\x64\xbd\x60\x05\xb5\xb1\x73\xaf\x41\xb8\xd7\x10\xa8\xf1\xd3\xe5\xbc\xc3\xa0\x88\x5c\xd3\xfd\xd5\x01\x06\x01\x2e\xc2\x52\x72\x62\x13\xb5\x36\xc3\x98\x08\xf7\x0a\xfa\x64\xab\x03\x37\xaa\x3a\xbd\x58\xdf\xa8\xc5\xba\x4f\xb6\x3c\x58\x5a\xb1\x93\x5e\x42\x2e\x12\xb8\x51\x2b\x76\x62\x86\xfb\x46\xad\xd8\x37\xe4\xc6\xbd\x2e\x56\xb6\x6d\x22\x32\x54\xdb\xeb\x51\x8d\x7b\x63\x72\x31\x86\x6d\x85\x6a\x6c\x50\x6d\x2b\x54\xdb\x64\xdb\xbd\xce\x9b\xd8\x6f\x36\x93\xac\x39\x5b\x84\x8c\xb3\xc7\x5e\x9d\x1b\x7c\x84\xfa\xeb\xa6\x3d\xf1\xba\xf2\xb0\x3c\xbe\x60\x76\x09\xf9\x85\xbc\x54\x9c\x78\x21\x2f\x57\x6c\x11\xa2\x04\xc6\xd8\x4f\x08\x21\x63\x3c\x9f\xeb\x7a\x76\x80\xc1\xd8\x74\xb1\xea\x77\x65\xb6\x48\x60\xad\xce\xd2\xbe\xba\x1e\x04\xee\x52\xbd\x67\x49\xb3\x31\xd8\xd5\x2e\x72\xba\xb4\x45\xaf\xd1\x4d\x8b\x19\x02\x77\xf5\x10\xa6\x25\x88\xdb\x1c\x62\xd7\xd7\x7b\xd3\x23\x5d\xcf\x68\xed\x34\x09\xc8\x4c\x71\x49\x1f\x84\x52\x3d\x82\x8c\x9e\x3d\xcd\x13\xdd\x80\x08\x37\x2a\x37\x73\xed\x16\xe4\x90\xfb\x86\x7b\x6c\xe7\xb4\x45\x4d\x9a\x2d\xe9\xdd\x62\xb3\x5a\xad\x6d\xd9\x4e\x71\x0f\x21\x6a\xd7\x8e\xad\xca\xa9\x32\x74\x73\xb9\x80\x7d\x8b\x62\xeb\x90\xb2\xa8\x29\x18\xb9\xa1\x56\x86\x95\x70\xac\xd4\x9a\x2d\xbd\xb4\x2a\xf5\x24\x7f\xda\x2d\x9e\xf6\xf4\x53\xcf\x04\xa1\xf4\x50\x4c\xf8\x45\x7a\x89\x95\xe5\x68\x22\xa8\x71\xb3\x99\xc9\xef\xac\x44\x2e\xbf\x8d\x0c\xca\x74\x1e\xd9\x6c\x22\x14\x92\x18\x2b\xe5\x04\xc5\x84\x62\x77\x5b\x6f\x71\x87\x2e\x85\x38\x3b\xc9\x85\x18\x61\x66\x2f\xc7\xe8\xf5\x95\xdf\xb2\x97\x29\x60\xb2\xe7\x38\xb9\x2a\x25\x55\x05\xbb\xe6\xad\x91\xa5\xda\x56\x53\x62\x69\x00\x71\x2e\x5e\xfd\xe5\x43\x44\x17\xe9\xa5\x42\xa3\x56\x0a\x3f\xeb\xe4\xfc\xd4\x9b\xaa\x11\x52\xd5\xd9\x75\x82\x74\xb7\x45\x59\x34\x8e\xee\xbd\x0a\xd1\x91\x12\x88\x91\x7d\x6c\xb4\x3c\xfc\x6d\xc9\xf0\x5c\x72\x33\x2d\xb9\x19\x70\x92\xe6\x82\x4e\x10\x9a\x4f\x33\x71\xc8\x7b\x7a\x50\x0f\x80\xc1\xfd\x8d\x2f\x20\xf2\xf5\xb9\x09\x9f\x1f\x8a\x8c\x0f\x1e\x9a\x4f\x1c\x98\x4f\x17\xa5\x5a\x1c\x12\x7e\x28\x7a\xda\x72\x25\x5e\x37\x3e\x0c\xbb\x71\x1e\x68\x12\x91\xf4\x22\xbe\xec\x0e\x05\x8a\x80\x5e\xc4\x97\x20\xa1\xd5\x32\x71\xb1\x91\x76\x74\x59\x5c\x7a\x2b\x56\x9f\xf5\x01\x4a\xee\x17\xb9\x9f\xdb\x28\xe0\xaa\x19\x83\x42\x40\x43\x40\xa2\xfc\x31\x21\x1e\x8c\x89\x07\x7d\xc2\xba\xc9\xe1\xa0\xd9\x1c\x1f\x06\xd9\xe6\xed\x0d\x6c\x13\x74\x43\xe2\x8b\xe4\x12\xbb\x14\x26\x04\x5d\x91\xe8\x62\xac\x7f\x8c\xc8\x8d\x1b\xc0\x90\x5c\xb9\x81\x12\xec\xdb\x5b\x84\x4c\x4c\xa9\x29\xcc\xe0\x0e\x6e\xe1\x18\xae\xe1\x48\x15\x6e\x75\x2e\xe1\x4c\x15\x6c\x75\xf4\x22\x70\xd4\x6c\xa2\x19\x39\x72\x03\xb8\x23\x13\xc5\xa6\x53\x72\xa4\xf8\x0b\xce\x9a\x4d\x74\x4c\xce\xdc\x00\xae\x89\xd2\x90\xd1\x2d\x39\xd3\x1f\xae\x9b\xcd\x3b\x3c\x14\x68\x04\xc7\x90\x42\xab\xd5\xc7\x70\x2d\x74\xae\x89\x6d\x18\xc2\x58\xa9\x64\xfd\x16\x19\x19\x2f\xe4\x51\xfe\x65\x66\x20\xfb\x2d\x32\x33\x5f\x92\x16\xd9\x81\x71\x8b\xec\x18\xfd\x32\x1a\xa0\x6b\xdc\x6f\xb5\x72\x5c\x93\x1c\x57\x51\x53\xdf\xc6\x9b\xb4\x48\xa7\x5a\xfa\x0e\x17\x75\x8d\x8a\xba\x32\xe8\xa1\x40\x33\x18\xe6\xd4\x2e\xd3\xd0\xe9\xe6\x1b\xd7\x5b\x47\xf3\xf9\x74\x8b\x90\x5b\x1c\x08\x46\xaf\xbb\x75\x9c\x75\xea\x6a\x75\x1c\xaf\xaf\x63\x67\x61\x34\x59\xdd\x1e\x9b\x96\xa2\x45\x2d\x18\xb7\x5a\x0b\xbd\xe5\x90\x1c\x0e\xba\x79\x7b\xac\x41\x37\xe3\xbc\x5c\xd0\x9c\xdc\x2c\x79\xe5\x0a\x9e\x92\xa7\xf3\xf9\xc5\x65\x37\xa3\xd7\xe2\x95\x2b\x37\x80\x4c\xa1\x7a\x8a\x75\x8d\xc8\x3b\xcc\xa7\xd4\x7c\xee\x1d\x86\xc5\xf3\xd3\x5c\x82\x3e\x52\x33\x67\xe6\xa7\x70\xeb\x87\x70\xe7\x3f\xcd\x36\x93\x8e\x05\x71\xbe\xb3\xf1\xe4\xf3\xc1\x93\x37\x56\x4e\x9b\x6b\xb1\x6a\xdb\x5b\x1f\x6d\x54\x3d\x1c\xe6\x6b\x47\x76\xde\xec\x5e\xf8\x29\x1c\xf9\x21\xb9\x0f\x7d\x0f\x7e\xfa\x0c\xd4\x8b\xa4\xf0\x0c\x67\x7a\x86\x2a\x4f\x42\x6d\x46\x29\x3b\x35\x74\x43\x7c\x5f\xc3\xb0\xc0\x10\xba\x21\xd9\xc9\x76\xcf\x2b\x8a\x4b\xe8\xfe\x04\x06\x31\x84\xae\x50\x50\x82\xa4\x06\x6d\xe8\x26\x6e\x42\xee\x67\x7e\x6c\x30\x2c\x72\xea\x5b\xc7\x22\x77\x93\x96\x81\x2f\xcb\x2b\x51\xd1\x2e\x5a\x04\x2e\x50\x43\x5a\x4e\x48\x58\x25\x84\x01\x75\x7f\x42\x08\x69\xb6\xb8\x8f\x04\x12\xf0\x18\x52\xd5\xc1\x21\x1c\x29\xd1\xb4\x38\xaa\xd2\x60\x42\x1c\xee\x05\x29\x60\x73\xef\xbc\xee\x94\xfb\xd0\xef\x58\xfd\x26\xec\xb5\xf3\xcc\x92\x4a\x5b\xd6\x96\x7c\xcd\x1b\x6b\x84\x9d\x52\x52\x8d\x37\x8c\x44\xae\x30\x4c\xa5\xd6\x56\x9a\xb1\x55\x00\x09\x89\x8c\xf2\xac\x86\x20\xe9\x9d\x29\x7a\xa4\x7b\x0d\x91\x9b\x40\x8c\xfd\x47\xfa\x2d\x8a\x5c\x49\x04\x44\x6e\x4a\x62\xf0\x0e\x91\x92\x6f\x89\x3b\xc3\x85\x9a\x68\xaa\x0f\xc0\xcb\xaa\xc7\xfe\xe3\xe5\x82\x48\xd5\x95\xa8\x65\x25\x71\x8f\xdc\x84\x08\x83\x6a\x33\x22\xec\xdb\x38\x30\x6c\x21\xd5\xaa\x56\x4b\x6f\xc4\x22\xdd\x2c\xfc\xcf\x82\x01\x53\xcd\xc5\x63\x22\x4d\x9b\xf6\xb4\xfe\x55\x08\xef\x3e\x91\x99\x52\xd9\x37\x4a\x65\xbf\x54\x13\x55\xc5\x7d\xd3\x81\xad\x0e\x84\x20\x56\xb8\x86\xcc\x1c\xb9\x21\xd2\x65\xdd\x5c\x49\x0d\x47\xd1\xb8\x7f\x12\xf7\x59\x52\x2c\x3f\x13\xe2\x75\x27\x87\x37\xf9\x42\x36\xc9\xd7\x9e\x91\xb2\xfc\xc9\xb8\x77\x73\x31\xb9\xf4\xd5\x1f\x2d\xe1\x5b\x2d\xda\x42\x66\xe2\xeb\xa9\x40\x0f\xc9\xa0\xd9\x1c\x1c\x92\x61\xb3\x89\x52\xc2\xd1\xf6\xc5\xe4\x12\x46\xd9\xd8\x0e\xa1\xe8\x83\x5a\x0f\x14\x5d\xd0\xa5\x64\xb8\x28\xfa\x23\xb7\xcd\xc0\x03\xe1\x06\x60\xe7\x55\xb9\x12\x4b\x1b\x22\xda\x55\x97\xab\xc8\xdc\x47\x16\xb3\xc1\x53\xf5\x2c\xed\xa0\xc7\xa7\x62\x95\xa2\x2c\x6c\x45\xb9\x6e\x2b\x4b\x60\xb5\xa8\x94\xa5\x3d\xfe\x42\x0f\x5e\xe9\x24\x22\xdc\xda\x5a\x04\x49\x6e\x34\xc3\xe2\xae\x5c\x31\x5e\xf3\x39\x5a\xf5\xda\x78\x99\xea\x63\xdb\x65\xcd\xa6\xdc\x22\x84\x37\x9b\xb5\x2d\x4b\x09\xdc\x3a\x1d\xad\x77\xe2\x13\x10\x6e\x5a\x8b\xd3\xcf\x9c\x68\x6e\xaa\xbe\x63\xa8\x6f\xe4\xf3\x1c\xe9\x33\x2a\x29\xf2\x80\x17\x3a\x8f\x05\x5d\xa8\xf5\xa6\x6b\xdd\xa4\xae\xcc\xaf\x22\xbd\xb7\xea\xa5\x7b\x45\x84\x9b\xf8\xab\x3e\x91\xfb\x2b\x5f\x35\x61\xea\x0b\x37\x5d\xe4\x55\x1f\xf8\xf6\xd9\xac\x24\xcb\xf0\x22\xdd\x48\x87\x45\xe6\x1e\x0c\xd3\x23\xdc\x62\xfb\x0b\xe9\xde\x94\x2a\x1f\xcf\x43\x4d\x4b\x85\x09\x69\x7c\x58\xab\x7b\x95\x82\x8c\xa8\xa2\x5d\x56\xac\x55\x59\x4d\x11\x4f\x98\x90\x4f\xd8\x20\x16\x0c\xdd\x08\x94\xea\x58\x4c\x37\xc5\x40\xeb\xf5\x3c\x56\x26\xcc\x56\x56\x03\x2e\x9d\x08\xf6\xe6\xb3\x45\xb6\xea\x67\x23\xc0\xa5\x7b\x64\x1b\x2b\x0d\x6f\x4b\x2d\x40\x42\xfb\xd5\xd6\x16\x0e\xdd\x84\x98\x59\xe0\xce\x8a\x21\x7b\xb4\x8a\x5d\x73\x2f\x89\xe9\xc8\xea\x97\x68\x60\xbb\x1b\x24\x29\xdc\xc3\xcf\xb2\x6d\xf8\xe7\x82\x0e\xb5\x9f\xb8\x48\xb3\x63\xf7\x4f\xae\x3e\x5f\xb0\x4b\xf7\xa8\xfb\x82\x2b\xcb\x92\x10\x92\xba\x61\x2f\x75\x13\x5f\xf5\x97\xfb\x53\x77\x97\x15\x25\xb5\x40\xd2\xbd\x33\xf9\x00\x8a\x06\x94\x49\x31\x88\x74\x6f\xb3\xa0\x87\xd4\x0e\x7a\xc8\xd6\xf9\xf4\x82\x2a\x4d\x37\x74\x8f\x20\x26\x3b\xda\x11\x11\xf6\x62\x53\x57\x9c\xd5\xd5\xad\x0d\x5b\x0c\x95\xa1\x0e\x5d\x71\x89\x17\xac\xd9\xd4\x51\x05\xcc\x0a\xba\x31\x29\x1b\xaa\x47\x47\x84\x9b\x20\x8e\xbb\x7d\xe3\xd9\xf4\x47\xa8\xe3\xe1\xc5\x02\xa5\x3a\x13\x09\xd1\x53\x14\x71\xc2\x8a\xf6\x59\x61\xa0\xaf\x44\x16\x5d\x69\x72\x4b\x29\x96\x3f\xbf\x9b\xb2\x9c\x35\x3e\x71\xc4\x5d\xc9\x6e\xe5\xd3\x98\x4b\xc6\xcd\xd1\xc2\xce\xd6\x1a\x50\xc7\x29\x3b\x29\xcf\x61\x40\x73\x17\x5e\x02\xf5\x93\xa3\xd6\xc1\x51\x41\x3e\xa2\x19\x8a\x05\xa4\x2e\xa7\x13\x06\xa9\xab\x2d\x44\xbd\x23\x52\x1e\xe6\xe7\xae\xa4\xc3\x13\x3a\x61\xae\x8c\xdf\xc4\x33\x26\x9e\xd2\x84\x21\x0c\x21\x39\xd1\x96\x45\xd9\x81\xc0\x4a\xef\x8f\xae\x2b\x24\x1f\xd1\x2b\x81\xe2\x0b\x76\x89\x21\x2c\xfa\xf3\x0e\x7d\xd5\x27\x60\x21\xac\xc4\x69\x08\xe0\x20\xad\x0d\x60\x1d\xc6\xa8\x53\x84\x1c\xa9\x3f\xfb\xea\x8f\x15\x08\xa9\x0f\xca\xe7\xd1\xfb\xe1\x43\x48\x49\xa8\xbb\x07\x28\x79\x25\xac\x28\x98\x0f\x95\x58\x8e\xc2\x4d\xce\xf4\x44\x23\x13\xa5\xa8\x0a\x35\x62\x57\x02\xa9\xb5\x4b\xad\x1e\xca\xe4\x5b\x94\x9b\xfc\xa7\x95\xed\x79\x43\x26\xab\x92\xc9\xd6\x92\xc9\x80\x5b\xa1\x12\x33\xed\x1a\x9f\x99\xe3\x05\x9a\xec\x50\x4d\x2d\x19\xc9\x31\x83\x58\x3d\x06\x71\xff\x0e\x22\xd5\x84\x78\x7d\x13\x9e\x73\x92\x76\x4d\x3b\xa8\x4e\x27\x40\xbe\x72\xe4\xa8\xa2\x0e\x46\x27\x18\x09\x37\x78\x94\xb5\x2e\x52\xeb\x4e\xac\x5a\x17\x43\x04\x8a\xad\x21\x22\x12\x9e\x73\xe2\x41\xa8\x9d\x2a\xe1\x4e\xb3\x89\x72\x22\x88\x3e\x69\xbd\x83\x4d\xf3\xe1\xbb\x58\x19\x94\x23\xd8\x8f\x94\x25\xf2\x88\x47\x13\xbd\x03\xf0\x5c\xd0\x09\xeb\xad\x7c\x5b\x89\x29\xb2\x62\xa9\x38\x74\xd8\xee\x83\x03\x0f\x5b\xd1\x3c\x1f\x04\x32\x9e\x58\x24\xb3\xd3\x35\x76\xe4\x35\x45\xf8\x3e\xd5\xda\x49\xda\xf3\x7c\xf4\x5d\x20\x8a\x41\xef\xb4\x76\x8a\x49\x56\x3b\xe5\x47\x38\x88\x1e\xd2\x30\x5a\xfc\x68\x65\xa5\xa3\xd4\x35\xcf\xfc\x34\x48\x52\xb2\x63\x47\xe8\x7f\x11\xe5\xe6\xfc\x19\x53\x5d\x33\x8e\x43\xdd\x22\x77\xa4\x16\x61\x97\xce\xe7\x23\xd4\xc1\x8b\xb5\xb1\x92\x2c\x86\x2b\x56\x09\x27\xc3\xf7\xa2\xd9\x1c\x45\x89\x8c\xc5\x9d\x3b\x8c\x91\xc0\xc0\x91\xc9\x00\xa1\x5b\x7a\xbe\x76\x17\x78\x35\xb6\x1c\x95\x32\x44\xce\x24\x95\x4c\xfb\xcc\x1d\xb0\xf0\xc2\x89\x58\x9b\x9d\x61\x33\xd2\x4c\x07\x58\x87\xf7\xbe\xee\xce\xb7\xbd\xf3\x0b\x58\xb1\x63\xe2\x57\x83\x95\xe1\xe3\x6a\xb6\x32\xbb\x05\x3d\xf3\x8f\x7f\x22\xec\x7d\xff\x6a\x10\xcb\x29\x47\xb5\x60\x3d\x3b\xb5\x29\xbe\x7f\xc5\x51\xaa\x83\xcb\xca\xfc\xa6\xcb\x3b\x40\xa2\xba\x03\xa4\x4f\x62\x5b\x84\xca\x35\x7b\x3f\x26\x9c\x6f\x55\x0c\x45\x76\x3e\xc8\x3e\x21\x25\x70\xef\x56\xea\x5d\x7c\xff\x58\xda\x7b\xf1\x6f\x32\x5e\x5f\x11\x99\x2b\xf0\xfd\x77\x61\x8f\x8b\x09\xa2\xcf\x03\xe0\xdc\x21\x93\xd9\x26\xed\x93\xbb\x57\x7d\x35\x57\x04\xe2\xbd\x63\x8e\x94\x4c\xc3\xfe\x35\x47\x63\xbd\xe1\x67\x26\xb1\x8e\x08\x16\xd5\x88\xe0\x32\x08\xef\x4d\x5d\xb4\xe4\xab\xd5\x85\xb8\x44\x18\x5e\x6d\x8a\x09\x96\x64\x39\x98\xe5\xa3\x70\x93\x50\xc4\xe3\xb1\x86\x84\x57\x8b\x7a\x50\x65\xb5\x65\x3a\x8c\x52\x22\x6c\x9d\x47\x90\x1b\xe2\x3d\xd6\x93\x9b\xd5\xfa\x86\x0d\x94\x19\x96\xff\x3c\x8f\xa7\x44\x66\x8d\x50\xb8\x3f\x0b\xf2\xab\xdc\x35\x85\xc6\x1b\x12\xd1\xa2\x87\xa5\xd7\x2f\x26\x5e\x37\x6c\x36\xe3\x43\x6a\x16\xd1\x48\x69\x33\x65\x02\x00\x65\xde\x13\x7e\x11\xb7\x5a\x7a\x23\xec\x42\xb4\x5a\x97\xcd\x26\xea\x78\x84\x44\x3d\x24\x5b\x2d\x60\xa4\x83\x7d\xc4\x5a\x2d\xd0\x19\x22\x08\x41\x07\xbb\x7b\x8f\x1e\x35\x23\xdc\xab\x95\xf3\x3b\xe5\xfe\xf7\x77\x14\xf6\x84\xdf\xee\x64\x11\x5e\xf0\x73\x53\xc4\xd9\x61\x61\x16\x55\xab\x90\x55\x4a\x71\x8f\x23\xe9\x26\x69\x90\x48\x65\x98\xec\x60\xdc\x13\xad\x1d\xbf\xdd\xf1\x39\x92\x17\xe2\x12\xf7\x9c\xbf\xb8\x76\xd7\x5e\x88\xcb\x5e\x7b\xc7\x17\xad\x8e\xfa\xda\xee\x2c\x30\xbc\x16\x9b\xd2\x3b\x54\xea\x51\xda\xcd\x02\xc3\x37\xb1\x32\xc3\x42\x97\x97\x56\x18\xcf\x15\x39\x59\x4d\xab\x60\xf6\xaf\xe5\xe1\xde\xa3\xf9\x7c\xff\x61\x99\x9c\x8d\x97\x5a\x15\x86\x97\x62\x63\xe6\x0c\xaf\x5b\xf6\x4b\x57\x94\xca\x69\x8d\xd8\xf6\xde\x23\xbd\x3d\x77\xe8\xcd\xe7\xfc\x90\xa4\x99\x27\x8e\x11\xfe\x07\x6b\xa5\x8b\x22\x26\x47\x98\x71\x78\x2f\x36\xa4\x8d\xf0\x56\xb6\x8d\xad\x6a\xdb\xde\xa3\x7f\xb2\xf9\x9c\xfd\x73\xff\x21\x8e\x06\xe8\x60\xdf\xfc\x7a\xe8\x69\xfd\x90\x1d\x3e\x7e\x38\x9f\x77\xbc\x9d\x43\x96\x91\x23\x49\xe7\xe0\x0f\xd9\x62\xed\x47\x0f\x8d\x5f\xaf\x78\xb1\xbf\xdf\xad\xbe\xd8\x7b\x54\x12\xcd\x75\xa8\x61\xf7\x57\xcc\x9f\x5a\x39\x19\x34\x43\xd3\x43\xaf\x97\xcf\x00\x9f\xb6\x78\xe9\xf7\x0e\x33\xe7\x4c\x5c\x9b\x06\xad\x16\xee\x2a\xa6\x8f\x7b\x88\x91\x0e\x48\x93\x29\x66\x89\xe9\x63\xdc\x6c\x2a\xd8\x45\xc1\xe6\x34\xe3\x70\x93\x99\xa7\xd2\xbb\x76\xb4\x61\x4d\x50\x9a\xb8\x0e\x4e\x38\x9b\x35\xbe\xbc\x7d\xf3\x52\xca\xe9\x07\xa3\x86\xa8\x91\x83\xbb\x01\x92\x84\x62\x65\x2d\x2f\xef\x41\x4f\x45\x3c\x14\x2c\x49\x9c\x8a\x44\xc9\xdb\xf8\x34\x9e\x4c\x53\x49\x83\x31\x6b\x36\x5f\xa9\xf9\x42\xd1\x7d\x48\x7d\xa5\x0c\xd0\x3e\xeb\x43\x18\xf8\xdc\x95\xb1\xa4\x63\xb3\x1a\xac\x08\x32\x70\x98\x10\xb1\x70\x2a\x31\x7f\xe8\x9a\xa3\xe9\x60\x6d\x09\x69\xd4\xa3\xe5\x32\xb3\xf5\x65\x14\x41\xb5\x02\xab\xcc\xbc\x15\xc7\x32\xc2\x03\xbd\xeb\x9f\x4c\x63\x9e\xb0\x8f\x1f\xde\x40\xf0\xde\xbf\x0f\x07\x3e\x77\x13\x49\x65\x9a\x40\xf8\xaa\x78\x3e\x67\xb7\x72\x01\xe1\x6c\xc5\xf1\x99\x20\x36\xc9\x4f\xca\x04\x6f\xe5\x54\xe0\x59\xfa\x18\xe7\x2f\xf1\x17\x77\x30\xac\xce\x64\x03\x14\x42\x63\x94\x28\x13\x2e\x67\x42\xc7\x6f\x38\xb8\xeb\x1d\xc6\x5a\x6f\x0b\x33\x89\x15\xf1\x21\xf2\x20\x56\x1a\xb4\xfd\x6a\xa7\x15\x63\x10\xe4\x0e\xbd\x1a\xd8\xb9\xbf\xcb\x35\xe2\x56\xa2\x3b\x65\xd5\xf6\x68\xcb\x01\x9d\xb1\x81\xfa\x14\x2f\xf4\x11\xd9\x22\xf4\x0c\x71\xb5\xbc\x1e\x8d\xc7\x1f\xb2\x5e\x79\xc9\x68\x9f\x89\x04\x61\x0c\xc1\x23\xab\xb7\xcc\x71\x2e\xbd\x37\x69\xfa\xe7\x70\xc7\xf3\xe6\xf3\x5d\xcf\x3b\x24\xf9\x2b\x5c\x88\x45\xa5\x9a\x93\xb2\xb0\xea\x4b\xb8\xe6\x68\x34\x50\xeb\x74\x57\x10\x81\x64\x4d\x6b\x38\x36\xb1\x7f\x3e\x5a\x5b\x78\x86\x26\x03\x93\xab\x4c\x2d\x9f\x88\x43\xea\x86\x53\x97\x6a\x95\x52\x8a\xbb\x7b\xee\xc6\x53\xc6\x51\xea\x86\xaf\xd5\xa7\x03\xd8\xf2\x96\x33\x5b\x68\xde\x1a\x0e\x14\xd4\x81\x42\xb3\xb5\x3e\x13\x4e\x38\xeb\x4a\x37\xe8\x9a\x84\x74\x3a\x88\x24\x9b\x69\xa6\x8b\xd4\x0c\x31\x89\xd3\xdc\x40\x59\xda\x05\xb9\x77\x53\x2d\xf8\xa6\x6e\x00\xdc\x9d\x45\x72\xf4\x54\xb0\x3e\xe3\x32\xa2\xe3\x44\x7d\x78\xac\x66\xa9\x70\xc3\x0e\x56\x16\xb3\x9b\xcd\x00\xf5\xa5\xe3\x52\xd3\xb0\x3c\x75\x41\xea\x06\x8f\xca\x28\x8c\x84\xf1\x3e\xba\x1d\x20\x86\x7b\x68\x05\x3d\x4e\x66\x3e\xb7\x15\x05\x8e\x39\x48\xcf\xdc\x00\xfb\xfa\xc9\x56\x42\x5c\x1a\xc4\x42\x22\xbc\xa8\x6b\x3b\xd5\x50\x53\x0f\x02\x5f\xba\x01\xd0\xca\x14\xe0\x44\x89\x86\xd2\xf9\x36\x43\xc7\x83\x22\x3d\xbd\xa6\xfb\xad\x58\x93\x32\xc7\x19\x3a\x5d\xee\x86\x6f\x9a\x4d\x24\x5b\xc4\x99\x38\x6a\x7e\x87\x61\xf6\x33\x72\xcc\x38\x96\xec\xfb\x81\x0d\x8f\x6f\xa7\x9a\xaa\xe5\x91\x3c\x96\x4a\xb3\x7e\xb2\x5e\xe7\xe7\xe9\x78\xac\x0d\xbe\x49\x56\x72\x73\xb6\x5a\xc8\x76\x11\x3d\x35\x33\x4d\xa8\x49\x9e\x1e\x08\x62\xd2\xee\x74\x69\xab\x75\xc8\x9b\x4d\x1d\x0e\xcb\x6e\x59\x88\x42\x8c\x9b\xcd\x78\xcb\x86\xec\x96\x08\xa3\x22\x82\xab\xdd\x81\x41\x16\xae\x12\xa9\xe9\x1d\xe5\x7e\x7e\xc2\x2e\xa2\xcb\xee\xe0\xa2\xdd\x8e\x2e\x49\xa0\x14\xe7\x40\xab\xcd\x69\x9e\x21\xf0\x3a\x00\x76\xe1\x5d\x02\x33\x22\x02\x28\x3c\xd3\x19\x01\x4c\x30\x4a\x5e\x69\x31\x9b\xcb\x57\x44\x42\x96\xbb\x50\xda\xcb\x8a\x49\xc4\x95\x79\x90\xbc\x22\x95\x5e\x6e\x00\xd5\x74\xcd\x68\x80\xc2\x56\xeb\x9f\x24\x2d\xb4\x10\xcb\xf1\x42\xc5\x50\x6b\xe7\x79\x18\x47\x7b\x17\xf2\x4c\xd4\x42\x35\x52\x14\xe9\xa3\x0a\xc8\x0b\x71\xd9\x95\x17\xed\xb6\x0e\x67\xbd\x95\x88\xe9\xc6\x16\x69\xfe\x75\x73\x39\x94\xe0\x4b\x55\xec\x5c\x42\x08\xcf\x0a\x55\x1f\xc3\xf3\xcd\x9a\x90\xcc\xc7\xd4\x1e\xcb\xca\xc8\x76\x79\x21\x93\xc3\x7c\x58\x19\xce\xf6\xcf\x8c\x06\x52\x04\xb0\x9a\x83\x41\x14\x32\x79\x8d\x71\x15\x71\xe1\xdd\xaf\xc1\x63\x0c\x2b\x07\xe6\xdd\x5a\x0b\x98\x37\x37\x65\xbf\xdb\x98\x5c\xef\x7f\x6c\x28\x29\x0e\x0f\xf9\x02\x77\x4f\xd6\xd6\x2b\xfe\xf9\x4f\xbe\x21\x89\xf2\x3f\xf5\xe7\x6e\x25\x77\x23\x5b\x77\xd4\xb2\x38\x4b\xf6\x8a\x4b\x26\x6e\xe8\xd8\xb6\x82\x5e\x71\xc4\x36\x9e\x24\x2b\x0a\x09\x5c\x3b\xeb\xfb\xc2\x8a\x6e\x6f\xcc\xd0\x53\x09\xce\x5f\xbc\xd1\x68\x34\x1c\x98\xa1\x57\xfa\x97\x03\xdc\xde\x0f\xf9\x64\x97\xb8\x43\xa7\x72\x6d\x03\x5b\x4a\xdd\xf7\x94\x24\x2b\x0a\x7f\xb5\x0b\x3f\x7e\x78\x48\x10\x27\x27\xfa\x18\x57\xb3\xc9\x0f\x49\x67\x67\xa7\x84\xfd\xd3\x82\x2d\xc0\x0e\xc9\x63\xaf\xd9\x3c\xd8\x3f\x24\x96\x3f\x94\xcb\x95\x90\xfb\x0f\x9b\xcd\xbd\x47\x15\x48\x61\x41\x1a\x62\xe6\xf3\x3f\xcd\x3f\x1a\x89\x75\x1d\x88\xac\x64\x2e\x28\xaf\xc8\xa8\xbc\x77\xa9\x75\x33\xc5\x9a\x12\xd4\x7a\xef\x38\xda\xa6\xd1\xf3\x43\x92\x37\x10\x4b\xb2\x0d\x91\x24\xa8\xe2\xa9\xb0\x0e\x32\x0b\x37\xd4\xa9\x8b\xfb\x90\xae\x63\xb3\x3b\x14\x4b\xe0\xee\x76\x4f\xfa\xa9\x8e\x9d\xa6\x6a\x84\xed\x8f\x29\xe8\x7f\x0c\x62\x63\x7e\xac\x39\x33\x68\xa2\x6a\xdb\x3b\x7a\x87\x6c\xbb\x9a\x70\x57\x69\x5e\x8a\x0c\x0e\x94\xdc\x69\xf7\x7a\x00\xd2\x0d\xe1\x0e\x45\x1a\x33\x48\x97\xe9\x74\xcb\x29\x08\x42\x41\x12\xa6\xcf\x7f\x0c\x56\x69\x8e\x0d\x5d\x68\xad\x1d\x38\x43\xa1\x04\x93\xbc\x58\x1b\x1e\x70\xa2\xb8\x08\x82\x95\xa8\xb8\xd2\xd3\x7f\x8d\x8e\xdb\x98\x12\x49\x3a\x30\x96\x64\x07\xfa\x92\x78\x70\x23\xd7\xca\x8e\x05\x86\xed\x95\xba\x6f\x91\x5f\x02\x26\x72\xd3\x59\xe3\x22\x83\x30\x86\xd1\x06\x40\xcf\x06\x1c\x6e\x00\xec\xd8\x80\xd3\x35\xa4\x65\xa7\x09\x61\xb6\xe6\xfb\x4e\xf6\xfd\x4e\x92\x6f\x70\xfb\x0b\x24\xc7\x92\xa8\x7a\x17\x70\x2d\x09\xe7\x70\x24\xc9\x17\x38\x93\x64\xca\xe1\x6a\xf5\x80\xb4\x1c\x67\x01\x4f\xe5\x7a\x8f\xe4\x57\xe0\xf0\xd9\xa4\xb0\x85\x57\x6b\xe1\x9e\xa1\x19\xfa\x04\x26\x07\x0d\x86\x53\x49\x36\x32\xed\x96\xac\x67\x88\x66\x3a\x55\xaf\x61\x58\x7d\x85\x40\x9e\x2d\xda\x66\x50\xf8\x2e\xc9\x4f\xf8\xf0\x0b\xe4\x9d\x3c\x2b\x77\xa1\x92\x67\x35\x70\x48\x89\x68\x77\x74\x0d\xa1\xd4\xe5\xba\x9c\x30\x10\x24\x05\x49\xa8\xaa\xe0\x8b\x5c\x3f\x73\x3f\x98\x99\x73\xa2\x1a\x78\xbe\x01\xee\xbb\x82\x9b\xa1\x2f\x12\x3c\xf8\x24\x90\xc0\xed\x0e\x36\x69\xc4\x4f\xaa\x43\x90\x07\xf7\x5a\x26\xb5\x67\x25\x0b\xaf\xe4\x16\x15\x3d\xe1\x77\xbc\x9d\xbd\x3f\x90\x68\xeb\x0f\xb8\x55\x29\xd8\xc1\x6d\x9d\x88\xb2\x75\xb0\xbf\xbf\x7b\xb0\x80\x8f\x6b\x66\xf2\xa9\x84\x50\x66\x13\xeb\xcd\xdf\x21\x47\xbb\x36\xeb\x34\x9d\x22\xae\x54\x34\x9e\xad\xf7\x1d\x8c\x7d\xf3\xaa\xc5\x2f\x3a\xe5\xfb\x1d\x8c\xb5\xba\x03\xcf\xd6\x75\x9b\xf3\x17\xff\x8b\x23\xa7\x75\x25\x11\x6f\x75\x70\x0b\x39\xb8\xe1\xb4\x5e\x08\xf4\x59\x66\x49\x52\xe0\xf3\xca\x16\xcd\xd0\x4f\xd5\xdd\x27\x78\x01\x3f\x97\x91\x73\x3f\xe3\x8b\x15\xd9\x8d\xec\x23\x50\x5c\xf3\xde\x92\x17\xf6\x4d\x9e\xeb\xb3\x63\x12\x45\x94\x61\xb5\x45\x2a\x09\xe0\xd6\xed\x22\xe8\xab\x40\x6a\x01\xa0\x66\xa5\x12\x6a\xa5\x9c\xa1\x6b\x09\x42\xaa\x0e\x47\x4a\x6b\x52\xba\xb6\x66\xbf\xb4\xe7\xb8\x4e\x4b\xfa\xce\xc5\x3f\x74\x26\xb4\x7f\x5c\x3a\x86\xe3\xa9\x62\xc8\xe2\x88\x48\xa3\xd8\x88\xcf\xa3\x0d\x02\x08\x89\x73\x61\xfa\xca\xa5\xb8\xe5\x5c\x3a\x36\xde\x70\x13\x96\x1d\x3f\x3f\xa5\x43\xf5\x61\x11\x37\xd0\x53\x26\x76\x83\xfc\x54\x58\x44\x90\x70\x83\x9e\x73\x3e\x62\x8d\xd7\x49\xcc\xdd\x67\x2c\x8c\xfb\xcc\x8d\x39\x3b\x1d\x34\xa8\x6c\x5c\x25\x31\x77\x5a\x46\xfd\x70\xe0\xa3\x1e\x1f\xdf\x59\x02\x75\x70\xcb\x69\x0c\x68\x34\xd6\xf9\xde\x1a\x72\xc4\x1a\x83\x78\x3c\x8e\x67\x26\x5b\xd5\x95\x44\x9f\x04\x8a\xb1\x82\x9a\xd1\xbb\xc4\x77\xba\x35\xc5\x46\x29\x33\xba\x41\x11\xcc\xd0\xb9\x84\x67\x52\x47\xdf\x2c\x38\xa1\x84\x91\x58\x5f\xec\x92\x12\x61\x35\x31\xd3\x42\x9d\x0f\x94\x37\x22\x2e\xe3\x06\x5d\xd1\x02\x9d\x36\x8f\xc7\x8d\x69\x9c\x24\x51\x10\x8d\x23\x19\xb1\xc4\x69\x99\x46\xaf\x6f\xdf\x96\x53\x6e\xff\x86\x7a\xe0\x63\x9d\xc8\x3e\x1b\xf8\x88\xe8\xf2\xef\x44\x1c\x8c\xd9\xc4\x54\xa2\x9a\xac\x37\x59\xd7\x61\x6d\x39\xbe\x6a\xa6\xd6\xe0\xfc\xe5\xb2\xc3\xe8\x86\x71\x83\x41\xc3\x39\xb8\x85\x5e\x08\x34\x43\x67\x12\xf6\x40\x77\x5d\xf6\x3a\x54\xa2\xeb\xb5\xdc\x70\xb0\xd8\x5e\xb4\x20\xf4\x25\xf4\xf5\x21\x6c\xf8\xa6\x0f\x7b\xbf\x94\xe4\x07\xbc\x5f\x2b\xd2\x9e\x23\x81\x1f\x3c\x37\x46\xe4\x0f\x49\x5e\x4a\x34\x43\xef\x25\xec\xc0\xee\x0e\xc6\xf0\x56\x92\x5b\xf4\x5a\x09\xbb\x1f\x12\xbe\xa9\xff\x30\x3c\x91\x24\x82\xe7\xeb\x17\x6a\x7d\xac\x1a\xa2\xb5\xca\xb8\xa9\xeb\x9d\x24\xc7\xf0\x42\x92\xb7\xf0\x69\xf5\xda\x95\x67\xaa\x85\xaf\x6b\xab\xca\x2f\x71\xe8\xe9\xc4\xe0\xf0\xa7\x24\x2f\x81\x33\x72\x03\x82\xad\x76\x54\x77\x73\x83\x7d\x86\x38\x83\xdd\x1d\xe0\xc6\x8f\x15\x80\x34\xf3\x2b\xeb\x4a\xe9\xd2\x45\x9e\x5d\x8f\x95\xab\xd9\x47\x2d\x32\xcc\xaa\xa2\x8d\x74\xf9\xab\x7a\x5e\x4a\x24\x1e\xec\xee\x14\x72\xa6\xf0\x7b\x97\x04\xb8\xb4\xcb\xc9\x0c\x09\xa6\x25\x5d\x8e\x99\x2d\x63\xd6\x09\x09\x59\x8e\x79\x77\xe7\x0f\xe1\x32\x60\xe4\x45\x36\x62\xbb\x3b\x20\xdb\x1d\x8c\x81\x13\xde\x53\x3c\xe8\x0e\xb1\x2f\xdc\x21\x28\xec\x52\x61\x57\xa5\xbb\xc5\xd9\xf0\xd7\x12\x3e\x29\xa8\x01\x6e\x49\x98\xa1\xaf\x3a\x74\xfe\x8f\x1f\x12\x6b\xc8\x32\x63\x9f\x0d\x99\x71\x81\xfe\x8c\x21\x65\xe4\x0c\x28\xdb\xb0\x13\x93\x2d\xda\xe2\xd0\x2b\xdb\xcd\x18\x6c\x75\xe0\x7e\xe8\x33\x60\xbe\x7c\xb0\xbb\x33\xf7\x60\xe0\xa7\x79\x6a\x60\x92\x69\x56\x77\xe8\x89\x6e\x93\x76\xc0\x74\x95\x6a\x29\x88\x68\xab\x46\x12\x09\xcc\x8c\x16\x05\x86\x21\x25\xa9\x3e\xb1\xbc\xb2\xc3\xbc\x43\x5e\x9c\x22\xfd\xf7\xdd\x1d\x60\x44\xe3\x95\xc0\xdb\xd2\xda\xdf\x4b\x10\x65\xaa\xa6\xb6\x54\x35\x70\x38\x81\x32\xdc\xe3\xad\x5c\x60\x88\xd9\x0a\x1e\xdd\xe2\xee\xf6\x02\x22\x46\x06\x1c\x06\x8c\x04\x1c\x02\xb6\x59\x81\x4b\xaa\xdf\x57\x2c\x5c\x39\x67\xd7\x02\xb4\x3a\xb5\xc0\xac\x9d\x42\x5e\xe5\x97\x9b\x2d\x16\x30\x66\x24\x95\xd0\x67\x64\xf3\x39\xff\x7b\xba\xef\x53\x08\x94\xb0\xa0\xd2\x67\x10\x24\xbe\x84\x60\xe6\x73\x08\xdf\xfb\xba\x2f\x6f\x18\x11\x1c\xb6\xd9\xe6\x79\x39\x61\xe4\x4f\x18\xb1\xb5\x72\xe0\xb0\xd3\x13\xfe\x1d\x9a\x28\xd6\xdb\x36\xa7\x14\x15\xd7\x0c\x19\x49\x39\x4c\x37\x96\x73\x1c\x53\xd0\x83\xec\x8e\x96\x19\x5b\x73\x7a\xca\xd3\x61\x32\x15\xad\x06\x18\xd9\xdb\xd5\x67\x15\xf6\xf6\x09\x91\xbd\x8e\xef\x41\x4a\x58\x37\x2d\x23\x9b\x5a\xad\x32\xfc\xb6\x96\xfa\x5d\xc7\x44\x66\xbb\x54\xc5\x61\xae\x63\xd9\x15\xa4\xe3\xfd\x21\x5a\xd4\xda\x8d\x49\x09\x61\xbd\x63\xe9\xdf\x4a\x64\x6a\x6a\x0b\x5f\xe0\x05\xdc\xad\x9b\x12\x0a\xb7\xaa\x64\x3e\x9f\xa1\x1b\x06\xce\xff\xe5\x40\x8a\xad\x3a\x0c\x45\x33\x34\x64\xe0\xf8\xea\x9b\xa6\x26\x5b\xc6\xa9\x5e\xc6\xab\xc0\x21\xa1\xfa\xd8\xe7\x8c\xa1\x19\x1a\x31\x08\x5b\x1d\x9d\x08\x28\x93\x36\xb4\xb4\x1c\x8f\x65\x97\x92\x22\x37\xd6\xad\x44\x03\xd4\x67\x5a\x95\x9d\x32\x13\x4c\x4c\xf3\xc3\x2d\x8b\x25\xa0\x14\x8e\x65\xf1\x15\xc3\x2d\x5b\xb9\x18\x99\xd6\xb1\x7a\x83\xd2\xac\x41\x0f\x1c\x30\x0e\xa8\x54\x35\x28\x25\x69\x99\xaa\x2b\x41\x77\x86\x96\x91\x62\x54\x86\x35\x46\x4d\x59\x6a\x13\x94\x81\x29\x4c\x79\x9e\x0c\x38\x66\x2b\xec\x05\x43\x89\xac\x53\xc2\x32\x4a\x7a\x0e\x18\xcd\x8f\x99\x0c\xa6\xac\xa4\xe4\x16\xdd\xaa\x2a\x6e\xa5\xe9\x4f\xd6\xea\x80\xc4\x8a\x1e\x4d\x0d\xd3\xfe\xda\x2a\xa8\xe9\x19\x45\xca\xf5\x4a\x09\x44\xa5\x95\x7a\x36\x23\x44\x66\x84\xfc\x5b\x9e\x5f\x57\x59\x4c\xf7\x92\xc8\x92\x90\x3b\x74\x6c\x13\x22\x5b\x1d\x9d\x67\x4d\x93\x21\xed\x9d\x8e\x0c\xf0\x38\xbb\xee\xee\x88\x11\xc9\xe1\x8c\xad\x56\xa7\x8f\x18\xe8\x0b\xbc\xfc\x07\x0f\x1c\xe0\xb8\x37\x43\xd7\x6a\x92\xe9\x2a\x1e\x02\xc7\xd8\x2f\x61\x92\x0a\x50\xc7\x00\x3d\xd2\x40\x4a\xdb\xbf\x5a\x9e\x91\xdd\x2e\xf6\x16\xf0\x94\x91\x63\x0e\x7f\x92\xa7\x4c\xcd\xc5\x57\x6b\x79\x85\x95\xa9\x67\x98\x66\x62\x66\x0e\x9f\xd0\xfc\xbd\x61\xee\x98\x50\xf3\x3e\x36\x83\x15\x6b\xd8\xd8\x82\x35\x10\x56\x3a\x96\x14\x66\x3a\xe0\x6c\xa6\xe3\xb9\xf4\x2d\x0d\x2e\x85\x7d\xcf\x3b\x94\x3d\x6d\x24\x29\x32\x3e\x4a\xa5\xa0\xfa\xb7\xe8\x15\x33\x3e\x93\x56\x47\xab\xa0\x65\xcf\x2e\xa3\x12\x6b\xbe\x8a\xfa\xeb\xea\x8d\x0c\xa7\x6c\xfd\x46\x7b\x51\xbf\x67\x98\xe8\x7b\x85\x89\xec\x3b\x64\xee\xd0\x29\x83\xb5\x86\x7c\x28\xc1\xdc\x2e\x56\xb8\x56\x30\x7c\x60\xe4\x8c\xc3\x17\xb6\x2e\x64\x64\x86\x3e\xb0\x55\xfb\x6b\x4f\x19\x12\x3a\xe6\xc6\xa0\x39\xaf\x90\x2f\x75\xe8\xd9\x6a\x14\xe2\x77\x50\xcf\xb2\x4b\x7f\xf1\x42\xcd\x60\x53\xc5\x09\x23\xcf\x38\x7c\x5c\xbb\x26\x9c\x72\xa4\x31\x9e\x30\xd3\x46\x6c\xee\x2f\xd8\xe0\x67\xfa\xb2\xb2\x7a\x6f\x01\x48\x90\x19\xfa\xce\xe0\x63\x86\x0a\x74\xbf\x9e\x33\x14\x4a\x0c\x4f\x19\x3a\xc1\x90\xd9\xa4\x72\x43\x05\x9a\xb9\x17\x18\x9e\xf1\xf5\xbe\x95\x2f\x2c\x5b\xbd\xba\x6f\xb8\x7b\x4e\x93\x6b\x72\x1f\xf8\x7f\x42\xe8\xa7\x1c\xfa\xbe\xe4\xc0\xfc\x67\x1c\x06\xc5\xa1\xe4\x32\xa2\x88\x59\xca\x03\xfd\xd3\xdf\xea\x40\x10\xf9\x8e\x03\xc1\x55\x25\x8d\xea\xb3\x0a\x5c\xdf\xbf\x89\x21\xf8\x52\x81\xf8\x6c\x41\xa0\x19\x1a\xc6\x5a\x78\xea\x39\x3d\x8a\xa1\x03\x1c\xfb\x1c\xb7\x9c\x07\x74\x1a\x3d\xb8\xd9\xb1\xee\xfd\xfb\xc9\x36\xe6\x77\x7d\x5d\xfd\xbc\x5f\xfb\xfc\x8d\xad\xf2\x71\x95\x39\xf7\xaa\x9f\x77\x6b\x9f\xdf\xb3\x8d\xc9\x63\x7f\x54\x3f\xef\xd5\x3e\xbf\xdd\x5c\xf7\x93\xcd\x75\x3f\xdf\x8c\xfc\xdd\xe6\x76\xbf\xd8\x4c\xf9\xa7\xcd\x9d\xfa\x75\x33\xe5\x7f\x6e\x2e\xcd\xd3\x8d\x94\x8b\x74\x23\xe5\x32\xdd\xd8\x2d\xac\xfa\xb9\xf3\xb8\xf6\x3d\xdd\x5c\x9c\xa6\xf6\x46\xb5\xd6\xf0\x4d\xeb\x60\xb5\xd3\x27\x56\x16\xc2\x0c\x3d\x89\x33\x9f\xa3\xf1\xc8\x58\x57\x75\xa7\x9b\x6f\x15\xbe\x43\xaf\x35\x0a\xb3\x79\x5b\xde\x94\x9c\x56\x32\x89\xbe\x8c\xeb\x9b\x82\x43\xb4\xad\xa5\x82\xc4\xb9\xc3\x6c\xc6\xac\x0d\x61\xe1\x6e\xf7\x68\x8a\xfe\xf1\x8a\x9b\x1b\x23\x22\x2e\xd9\x90\x09\xbf\xe1\xfc\xa3\xc5\x5b\xff\x70\xfe\x81\x7d\x11\xe9\xcd\xfe\x62\xef\x2f\x45\x59\x1a\x6f\xd6\x37\x7e\x11\x89\x5b\xc8\x69\xf4\xa3\x61\x24\x13\xd0\xf9\xf1\x87\xb1\x34\x9f\x74\xdd\x4a\xf4\xc0\x9f\x31\xfa\x14\x23\xae\xb7\x03\xcb\xf4\x47\xa9\x6d\x79\x58\x17\x05\xa7\x88\x97\xa7\x5c\xa9\x3e\xf6\x10\x40\x48\xb6\xb4\xaa\xd9\x5d\xd1\x4b\xd9\x16\x16\xea\x47\x90\x02\xd7\xbb\xf9\xc1\x31\x70\x97\x7e\xd0\x7b\x16\x7a\x23\x91\xea\x9b\x9c\xcc\x6d\x8d\x61\x71\xfa\x0c\x49\x68\x77\x94\xf4\xa8\x0c\x11\xc5\xd8\xd7\x5d\x1e\x82\x07\xf7\xf4\x83\xf6\x42\x94\x79\x09\x02\x65\x5e\x1c\xfb\x4c\x8d\xb8\x4b\x17\xf6\x88\x04\x36\x63\xdc\x44\x68\x86\xc6\x91\x49\xef\xfa\x48\xf3\x87\xdd\xfe\xc4\x86\x55\x1d\x9b\x0f\x43\x9f\xde\xf9\xa6\x07\x2b\xdb\x63\x63\xbb\xbf\xd0\x0c\x6d\x47\xb0\x07\x1c\xcf\xe7\x5b\xfa\xb9\xe3\x79\xc0\xb5\x0b\x4f\x7d\xd0\x3f\xec\x4b\xee\xad\xc2\x08\xf1\x36\xe9\xe0\x07\x7b\x73\x0f\xb7\x11\x7f\xd0\xf1\xbc\xb9\x87\x5b\x88\x3f\xd8\xd3\x4f\x56\xda\xa2\x5f\xf2\xe5\x50\x35\xef\x6d\xac\x43\x4f\xcb\x74\x38\x69\x05\xe6\x36\xaa\x0c\x48\x60\xdf\x6a\x3d\x49\xab\xfa\x5c\x04\x77\x51\x65\x5f\x6f\x94\xfe\xe6\xa6\xe0\x1d\x3a\x8d\x74\xa6\x7d\x73\x17\xc0\x02\x43\x10\x57\x30\x0d\x6d\x4c\xbc\xe7\x48\x91\x32\xc7\x77\x06\x74\x9c\x30\x6b\xa5\x98\x56\xc0\xdc\xed\xf9\xdc\x71\xb6\xb2\x2b\xa5\x95\xa2\x58\x9e\x8e\xb7\x01\x7f\xaa\xb1\x3e\x8b\xe1\x75\x04\x47\x12\xf1\x96\x43\x9c\x0a\xb3\xdf\xa5\x6b\xb7\x07\x9d\xef\x4e\x76\x25\x6b\x75\x9f\xf0\xb6\x42\x08\x29\x59\xc9\x08\x2b\x5c\x9d\x18\x84\x57\x62\x47\xfe\x05\xb3\x62\x3e\xf7\x0e\xc9\x1d\x7a\x17\xaf\xcc\xf9\x2f\x6d\xda\x17\xa0\x2f\x39\xf8\x2f\x4f\xa4\x6e\x11\x72\x55\x76\xc3\x71\x95\x43\x7e\xa8\x4e\x70\xec\xfb\x77\xaf\xd3\xcd\xb9\xd9\xd3\x8d\xcb\xcc\x99\x3d\x31\xb8\xbb\xdd\xbb\x4e\xfd\xa3\x14\x9b\xab\x19\xca\xb3\x7e\x9b\xeb\x78\xba\xb9\x8e\x57\xd5\x26\xbc\x50\x4d\x78\x17\x59\xe8\x4f\xab\x00\xf9\x40\x1b\x3c\x76\xc6\x75\x1b\x6e\x90\xa2\xd3\xb4\x2a\x22\x3e\xd8\xf3\x75\x1a\xa1\x67\xe8\x62\x86\xa2\x08\x44\x84\xae\x52\xe4\x61\x0c\xdf\x53\x74\x9c\xea\x4d\x0a\xd0\x5f\xf2\xcf\x4f\xf5\x4b\x78\x95\xa2\xe5\xc1\x76\xfe\xfa\xcb\x8c\xf2\x3a\x80\x2d\x6f\x91\xe3\xfb\x0d\x54\xe6\x90\x60\x71\xbd\x2f\xbe\xb4\x5b\xf0\xa5\x36\xfb\x32\x77\x44\x75\x34\xce\xab\x40\x3a\x1e\x87\x67\x81\xec\x65\xa2\xf8\x1a\x50\xf9\xe5\x63\x6a\x6f\x20\x05\x5f\xca\xb8\xad\xf0\xb8\x85\x66\xa8\x3f\x00\xc7\x81\x19\xfa\x19\x01\x93\x70\x9e\x2a\x29\x3e\x00\x3d\xbd\x4f\x52\x78\xa7\xea\x3a\xc5\x18\xde\x47\x6a\x71\xd3\xcb\x64\x4b\xa8\x7f\xca\x1a\xde\x54\x6b\xb8\xd5\x3e\x9d\x73\xbd\x75\x73\xa6\xd3\x74\x7d\xd0\x93\xf7\xa5\x4e\x19\xfe\x1d\xf8\xf2\x66\x4e\x32\x28\x08\xa1\x38\x8b\xe6\xdb\x2e\x6f\x2e\xe3\x76\x62\x70\xad\xfe\x6b\xf2\x3e\xa6\xe6\xdf\x5b\x09\xdf\x22\xe4\x0c\xa2\xb1\x64\x42\x09\xa2\x6c\x43\x27\x24\x33\xf4\x39\x5a\xad\xa4\xcc\xd2\x5c\x7a\xe2\x05\x9c\x23\x0e\xcf\xd0\xc5\x29\x72\x92\x68\xcc\x78\xc8\xfa\x8e\x32\xdd\x87\xa9\xa1\x6a\x4b\x7b\x11\x30\x86\x53\xe4\x44\x7c\x14\x05\x91\x5c\x86\x60\x39\x04\x0d\xa5\x4e\x97\x64\x7f\xf6\x20\xcd\x3f\x0b\x16\xb2\xe8\x86\x09\x07\xa6\x86\x73\x4e\x91\x33\x14\x71\x3a\x75\x20\x54\xcc\x51\x2c\xf9\xde\xe1\x27\x81\x42\xdc\x73\x7a\xf9\xde\x44\x53\x81\xf8\x8e\x25\xbd\x9f\xa5\x99\xea\xd3\x36\xc7\xd2\xb6\xe7\xf3\xec\xa9\x6f\x3d\xb3\xb2\x2f\x79\xb7\x04\x66\x06\xc8\x3c\xd0\x72\x00\xfb\x7a\xfc\x18\xe4\xdb\xbe\x52\xa7\x7c\x97\x3a\xe5\xbb\x74\x59\xe9\xf5\x39\x8b\x94\x0d\xa2\x45\x6d\x08\xfa\xa7\x39\x36\xac\x63\x2d\x74\x12\x16\x86\xf3\xf7\x79\x62\xd0\x22\x0d\xb5\xae\x28\xca\x2a\x8a\x74\x45\x91\x1b\x82\x24\x88\x92\xc8\xed\x63\x55\x9e\x50\x97\x41\x48\xa2\x5a\xa5\x1e\x50\x37\x00\x9a\x57\xba\x44\x43\xec\x06\x10\xbb\x21\xc4\x6e\x1f\x62\x45\x83\xc4\x39\xa4\x22\x43\x68\x32\x4a\x23\xeb\xbf\xd2\x87\xfd\xbc\x0f\xfb\xcb\x7d\xa8\xba\x80\xe9\x06\xa6\xfa\x96\x5b\x4a\x98\x1b\x42\x48\x98\x22\x8b\xb0\xa5\x9e\x8c\xf4\x02\x37\x20\x2b\x7a\x53\xea\x85\xab\xec\xcd\xfc\xe0\xbe\xe9\x4d\xbb\x20\x23\x48\x5f\x61\x85\x75\xb5\x48\xcd\x1c\x86\x75\xe5\x5c\x57\xce\x75\xe5\x7c\xa9\x47\xf3\x20\x94\x8c\x16\x24\xd4\x80\xe3\x95\x83\xd9\x81\x08\x06\xc0\x96\x68\xb1\xfa\xf4\xe7\x92\x1a\xf3\x6d\x00\x49\x55\x41\x79\x5d\x85\x49\x82\x62\xf3\xbb\x34\x44\x6b\xea\x52\x00\xf7\x61\xa8\xec\xe9\xf0\x8d\xbf\xd5\x59\x54\x60\x5f\x56\x61\x8f\xb5\x02\x30\x51\x0d\xd1\xff\x2a\x8d\xa2\x3f\x80\xb3\x00\xbe\xa5\xc8\xb9\x68\x5f\xfc\xf5\xd7\xe5\xfd\x02\xe1\x3f\x5a\x3d\x17\xfe\xfa\xeb\xaf\xbf\xfe\xc7\xf6\xfc\xdf\xfe\xfa\x2b\xb9\x74\x30\x86\x3b\x74\x15\x68\x87\xe6\x59\xbc\xfa\x90\x4b\xf8\x72\xa1\x14\x1f\x25\xdf\xb1\x71\x38\xd4\x6d\x9c\xf7\x75\xa1\xed\xdc\xe7\xd3\x18\x74\x4c\xd8\x77\xa6\xe4\x17\xc7\xb8\xe5\x2c\x9c\xca\xa4\xfe\xb1\xd9\x1a\x7b\x5b\x5b\x9c\xeb\xab\xf3\x93\xda\xf7\x47\x75\x1b\xb9\xfa\xbd\x6e\x0b\xbe\xab\x7e\xae\x97\x7e\xf1\xfb\x0a\xea\x1d\xaf\x2a\xa8\xf7\xd5\x01\xfb\x64\x63\x7a\x91\x22\x23\x80\x39\x9d\x30\x07\x4e\x02\xa4\x46\xcd\x48\x47\x93\x2e\x29\x7b\xf7\x25\x13\xc3\xc9\x07\x36\x64\xb7\x0e\xbc\x55\x4b\x45\x30\xcc\xdf\x1e\xff\x48\xe9\x58\x75\x6f\x7f\x00\xe7\x81\x59\xd5\xde\x0e\x14\x0d\x03\x5c\x5b\x7b\xbf\xa6\xab\xc3\xcc\xfe\xb4\x56\xb3\x19\xfa\xa8\x18\xa1\xb3\xb7\xe7\xe1\xd6\xc3\xce\xe3\xbd\x83\x47\x4a\x42\x89\x43\xaf\x27\xda\x9d\xbd\x03\xef\xf1\x81\x2f\xf0\x03\xfd\xf4\x70\xee\xa9\x59\x6a\x5e\x3f\xfc\x43\xaa\xe9\xc7\xda\x88\xe9\xaf\xda\xe2\x60\x0f\x76\x0f\xf6\x77\x8c\x1d\x62\x5e\x3f\x3e\x98\x7b\x18\xab\xd7\xf3\x3c\xea\xf5\x9e\x7e\xf2\x11\x27\xac\x8d\x76\x0f\xf6\xff\x48\x5b\x28\xcd\x2c\x97\x34\xb3\x5c\x30\x6e\x23\xd4\xd9\xdf\xfd\x03\x09\x82\xf6\xff\xe0\xad\x1d\xfc\xa0\xb3\xbf\xab\x6a\xd8\xc1\x0f\xf6\xd5\xbf\x1d\xa0\xb1\xcf\x88\x68\x21\x71\xd8\xf1\x7a\xbb\x7e\xfb\x31\x86\xa0\xe3\xa7\xad\x3d\xcf\xfb\x43\xb6\xd0\xce\x21\xeb\x79\x7e\xc7\xb6\x62\x38\xad\xcc\x9f\x27\x01\xec\xc1\x0c\xbd\x0b\xe0\x45\xa0\xb9\x14\x39\x6d\xc5\xc0\x4f\x02\xd8\x81\x55\x9b\x60\xf5\x2d\xb0\x4e\x6d\x0b\x6c\xa7\xb6\x05\xb6\x5b\xcb\x78\xb0\x57\xcb\x8f\xb0\x5f\x3b\xe6\x7d\x50\xbd\xb1\xb0\xf1\xb0\x76\x5b\xe0\xa3\xda\x01\xfb\xc7\xb5\xeb\xad\x3a\x5e\xfd\xba\xaa\x4e\xa7\xbe\x0b\xd7\xd9\x59\x2c\xd0\x0c\xbd\xcc\x1b\x5d\x6d\xf5\x0c\x7d\xb6\x7a\xe3\xdc\x7a\xff\xd3\x7a\xef\x5b\xef\xbf\xad\x79\xff\xdc\x7a\xef\x66\xef\x77\x61\x86\x5e\x17\x15\xeb\xff\xb5\x9c\x6f\x96\x58\x10\xb4\xa2\x65\x0d\x4d\x6e\x50\x23\xee\x83\x01\x56\xcb\x50\xb9\x01\x71\x1f\x1e\xfb\x5a\xee\x9d\xfa\x5b\xa2\xd9\xd4\xf7\x91\xcf\xe7\xb2\xa7\x9f\x77\xfc\x5d\xbf\xa3\x7d\x8d\x6e\xf0\xc5\xf6\x22\xd9\x2c\xc0\x0f\xbd\x4c\x1b\xa5\x09\x5a\x39\xd1\xeb\x41\x3a\x5c\x5b\x58\xc2\x8a\xb9\x69\x9c\x22\xf1\x80\xcd\xbd\x1e\x6f\xa1\x2b\x69\x9e\x71\x0b\xc9\x96\xd3\x70\x30\xf6\x95\x84\xdd\x8e\x8c\x63\x7e\xa1\x27\xb0\x03\x3c\x52\x3a\x3e\x84\x09\xd6\x27\x28\x4a\x17\x96\x45\xdb\x56\xe1\x0d\x68\x36\xb7\x6c\x77\x40\xee\x1c\x30\xfe\x00\xcb\xbf\x65\x37\x4c\x4d\x2b\xe3\x12\x50\xda\xef\x20\x01\x0e\x7b\xb8\x9d\x3d\x75\x3c\x0f\xb7\xf2\xb7\x9e\x67\x53\x40\xe9\xff\x1f\xd9\xbd\x74\xca\xd9\xcd\xd3\xf1\x04\x1d\xc5\x89\xf7\xd5\x66\x79\xb5\x66\x75\x6a\xcd\xda\xa9\x35\x6b\xb7\xd6\xac\xbd\x5a\xb3\xf6\x6b\xcd\x3a\xa8\x35\xeb\x61\xad\x59\x8f\xea\xad\x7a\x5c\xbf\x5e\xae\xe3\x2d\x35\xb3\x63\x3b\x11\xad\x59\x84\x98\x52\x0a\xf4\xb0\x6b\x99\xad\x6f\x58\xe2\x6a\x46\xe9\xd7\x4a\x67\xd3\x02\x5b\xbf\x97\x05\xb8\x52\x95\x3a\x7b\x07\x1d\xfd\x9a\x55\x60\x0b\xe5\x5d\xc9\x59\xd1\xea\x78\xde\x1f\xbc\xb5\xf7\x87\x6c\x31\x97\xb6\x10\x73\x83\x5e\xc7\xb7\x3d\x4e\x91\x4d\x8d\x20\x8a\x38\x22\x08\xc7\x70\x4f\x13\x9f\xb7\x53\x8a\x84\x16\xdc\xc2\x0e\x44\x1e\x27\x4a\x2f\xec\x68\xf5\x90\x26\x16\xb6\x81\xcd\xe6\x8f\x0e\xf6\x98\x66\xf4\x87\x9d\xc7\x9d\x03\xfb\x6e\x97\x80\x56\x96\xf0\xa3\x04\x3a\xbb\x46\xee\x58\xde\x3a\x5a\x8f\xb5\xee\x6d\x4b\xe4\x9c\x8d\xe2\x74\xdc\xd7\xb7\xee\x06\xac\xc1\x26\x53\x79\xe7\x60\x7f\x86\x4e\x13\xb8\x91\xc8\xf9\x2c\x62\x3e\x6c\xbc\x3a\x3b\x7d\x74\xe0\x75\x1a\x83\x58\x4c\xa8\x74\x30\x4c\x6a\x76\xfb\xd8\x26\xe0\x03\x9a\xc6\x70\xff\x41\x09\x9a\x2d\x0f\xc3\x59\xfe\x70\x9e\x3f\xbc\x54\x0f\xef\x95\x25\xf5\x9d\x81\xa0\x5a\x3c\xda\x5e\x82\xbe\x8d\x8d\x6a\x71\xc5\x31\xde\x40\xee\xb4\xea\x78\xba\xa9\xc8\xd5\xf0\x58\x5b\x3f\xa7\x46\xa6\x7d\xa9\x46\x1e\x66\xb3\x43\xd6\x27\xff\x29\xda\xea\xc0\x96\x57\xcf\xb6\x69\x5e\x77\xea\x59\x79\x4e\xd1\x96\xa7\xa1\x6b\x7c\x6a\xde\xab\x45\x19\x61\x9d\xe6\xb0\x10\xe6\xc1\x40\xf5\x41\xea\x06\x18\x82\xa1\xcf\x21\x98\xf8\x42\xc9\x6f\x66\x7b\x21\xab\xcb\xc3\x55\x37\x1f\x3c\x6d\xa7\x04\x91\xee\x90\x77\x63\xa6\x48\x09\xe3\xc9\x74\xcc\x24\x6b\xd0\x7e\x3f\xe2\x43\x1d\xd1\xa6\x0f\x23\x29\xf3\xd9\x17\x6e\xd0\x9b\x4a\xd3\xdf\x37\xfa\x2a\x4f\x5f\x95\x7d\x6b\x00\x92\x06\x15\x4c\x27\x9e\x88\x04\xeb\xdb\x9e\xa9\x49\x95\xaf\xde\x27\xb0\xa3\xd8\xea\x16\xbd\x4e\xa0\xd3\x81\x8e\xfa\xa1\xd9\x6d\x27\x5f\xe5\x2c\xbf\xe7\x32\x4f\x76\xea\x3c\x39\xa4\x1b\x37\x58\xa6\xd5\x0e\x08\x4d\x02\x96\x8f\x66\x20\x4f\xb5\x1f\x82\x7e\xd6\x76\x50\xa2\xed\xa0\x9b\x42\xe1\x3a\xf3\x67\x68\x30\x86\xbe\xd2\x55\xe9\x19\x06\xfa\xb1\x78\x21\x31\xdc\xf8\x21\x24\xe6\x45\x38\x06\x8a\x81\x7e\x36\xbf\xde\x24\x6a\x46\x7f\xc1\x90\x62\x08\x42\x35\x22\xa7\xe6\x43\xa2\x03\x9b\x5e\x2b\x13\xc5\xf2\x9f\xda\x2d\x54\xc6\x23\xe2\x44\x8f\x19\x76\xb7\x7b\xd1\xd8\x57\xad\xab\xb8\x7d\xee\xe8\xc6\x1d\xa1\xdb\xcd\xbd\x71\x6c\x57\x37\x1e\xa0\xc9\xb8\x3a\x07\xaf\x37\x17\x3f\xa2\x9b\xdd\x88\x9b\x3f\x5f\x55\x14\x89\x6a\xbe\x1a\xcb\x8d\x58\x15\x7e\x5a\x67\x3f\x31\x2a\xfb\x0c\xbd\x19\xeb\x98\x85\xd2\x64\xfb\xeb\xaf\x9e\x71\xed\xb8\x74\x1f\x63\xec\x06\xbd\x53\x9d\x59\x5d\xb8\x81\x71\x89\xe5\xf1\x9b\xc2\x0d\x74\x8c\x03\xf6\x4f\x91\xf3\xc0\x81\xe3\xe2\x38\x8f\xd9\x3b\x1e\xc3\xc7\x31\x7c\x40\x1c\xee\xe9\xbe\x7f\x2c\x81\x4a\x5f\xe1\x09\xdf\x2b\xc6\x5f\x60\x3d\x1e\xd7\xb1\x7a\x67\xb9\x34\x2d\x52\x35\xd9\xdd\xa5\x44\x64\xf9\x92\x67\xee\xc0\xa7\xba\x7c\x75\xf1\xbb\xdf\xf6\x1f\x56\x3e\xec\xf8\x15\x33\xab\xfc\xb0\xeb\x57\xcc\xb3\xf2\x83\xe7\x57\xb6\x00\xcb\x0f\xc5\x82\xfa\x79\x5c\x5b\x51\x7f\x8e\xeb\x72\xe6\xd9\xd8\x1a\xaa\xd3\xea\x48\x76\xea\x43\xf9\xbd\xfa\xfd\x61\xed\xf3\x87\xea\xe7\x83\xda\xe7\x2f\x56\xbf\xbd\x91\xd6\x5e\x5c\x27\xbb\xd5\x83\xfb\xca\x8a\xd1\x9a\x23\x76\x95\xbd\xf6\x23\x82\xaf\x63\x3d\x13\xaa\x57\xe6\x9e\xd7\xcc\x93\x31\x3c\x43\x17\x3f\xc6\xc8\xa1\x63\x26\x64\x43\xff\x6d\xcf\xa8\xe0\x11\x1f\x3a\xf8\x12\xab\xcf\xef\xc6\x48\x13\x50\xb5\xfb\x4e\x6c\x4c\x7f\x32\xc4\xd5\xd2\x22\xfa\x3a\xaa\x51\x6b\xcd\x14\x4e\x7d\x2f\x53\x8f\x17\x15\x29\xf5\xb1\x4a\x44\xda\x87\xfc\xda\x85\x80\x55\xa7\xd7\x9b\x2a\xe4\xfb\x31\x38\x23\xc1\x06\x0e\x3c\xf8\x1f\x57\xf4\x86\x9a\xeb\x4f\xfc\x07\x91\x2b\x59\x22\x11\xe2\x84\xe3\xe2\xb0\xe3\x83\xbf\x92\x07\x43\x70\x1c\x8c\x75\xce\x5d\x0b\xeb\xb3\x2a\xd6\xef\xac\xbe\x03\x6a\x79\x4d\xdf\x99\x5e\xac\xfb\x4e\x07\x7d\xd5\x33\x9a\x3c\xe8\xf7\x91\xf3\x3d\x18\x53\x7e\x6d\xf5\x18\xd7\xbd\x05\x1f\xd5\x84\x4a\xfa\x60\x72\x99\x9d\x54\xba\xe1\x73\x45\xd2\x2a\x95\x89\xdb\x11\x3c\x93\x3e\x9c\x80\xf6\xc5\x6f\xf7\xf3\x51\x92\xec\x56\xb6\x79\x3c\x13\x74\x6a\xd5\x25\x5a\x8e\xaf\x7e\x62\x98\xa1\x9b\x02\x76\xd6\xee\x78\x9e\x81\x5a\x1e\xbd\x9f\xd5\x2e\x18\x14\xa5\x02\xc9\x1b\x81\xe4\xed\x38\x95\xe3\x88\xb3\x76\xc4\x07\x71\x23\x88\x45\x9f\x89\xb6\xe7\x60\xd0\x4d\x36\x35\xcf\x90\x2c\x8a\x0d\x68\x63\x40\xdb\xba\x44\x38\xa2\x42\x36\x26\xa2\xbd\xa3\x2b\x3f\xc1\xf0\x6e\x8c\x9c\xb3\x38\x15\x21\x73\xaa\x54\xbc\xde\xdc\x03\x25\x77\x2a\x8a\xb4\x77\x57\xe3\x6d\x4c\x82\x0c\xb9\xa6\xe2\xf9\xb8\x4e\x7c\x32\xc9\x49\x16\xd1\x70\x24\xdb\x5e\x43\x77\xdc\x24\x95\x6a\xa9\x85\x19\xa2\x7d\x70\xd2\x84\x89\x76\xc2\xc6\x2c\x94\x0e\x38\x11\x8f\x64\x44\xc7\xc5\xd7\xf6\x24\xfe\xd9\xfe\x05\xc8\x8c\x05\xd7\x91\xfc\x05\x54\x46\x48\x18\x8f\x63\xe1\x80\xf3\x6f\x61\x18\x56\x86\xee\x1f\xa4\xd8\x37\x37\x23\xc8\xfb\xab\x9a\x33\x6c\x0f\x68\x9f\xf5\x2b\x63\x93\xb0\x30\xe6\x7d\x2a\xee\x1c\x0c\x1f\x29\x3a\xa1\xe8\x54\x47\x36\x61\x0c\x71\x1f\x39\xcf\xb5\x23\xbf\x11\xdc\x35\xe4\x28\x4a\x1a\x63\x1a\xb0\xb1\x55\xb5\xd3\xd2\xa3\x51\x19\x90\x6f\xb6\xbe\xfa\x6f\x0f\x32\x37\x7e\xf2\x80\xb3\x59\xcf\xec\x0b\x10\xa7\xf5\x3a\x42\xef\x6b\xaa\xe8\x4b\x6b\x20\xcf\x53\xc4\xdd\xe0\xbd\x1b\xbc\xad\x84\x0c\xfc\x4d\x26\xfb\x46\xd1\xd2\xcc\x2c\xf4\x9a\x97\x66\xcf\xd6\xcb\xf6\x1d\x06\x52\xd5\x38\xc2\xda\x35\xb5\x9a\x33\x03\x36\x1e\xb7\x93\x31\x4d\x46\xed\x78\x99\x37\x4d\x33\x75\x77\xf8\xe6\x74\x0b\x6c\x22\xb7\x4f\xf9\x50\x75\x6c\x85\x60\xbb\xbb\x9c\x96\xf8\x0d\x4a\xd6\xd1\xd1\xd7\x84\x58\xbd\xfb\xbe\x3a\x59\x67\xfd\xda\x29\xd6\x1f\xd5\xef\xcf\x2d\xa1\x1e\x0d\xb9\x62\xcd\x41\x3b\x64\x5c\x31\x43\x51\xa5\xe1\x81\xdb\xbe\xea\xb9\xd3\x1a\x17\xbc\x5d\x21\x9f\x47\xaa\xcd\x0e\xe8\xfb\x9f\x38\x9c\xf6\x6d\xf8\x27\x9b\x95\xa0\xe7\x74\xa3\x23\xf6\xdd\x6a\xc3\x81\xdb\xbb\x6c\x99\xea\xbe\x25\xe7\x73\x7d\x16\x54\x2b\xf0\x3b\x26\x15\xbb\xbe\x33\xa8\xd0\xe5\x2b\x4e\x56\xbb\x1d\xab\x18\xaa\xe2\x05\xe2\x6e\x30\xc8\x9c\x41\xb2\xea\x05\xca\x39\x2e\x98\xc0\x3a\x2f\x90\x76\xa9\x2e\x6a\x27\x93\xed\xea\x4f\x11\xd7\x09\x2b\x4a\xbf\x69\xb5\x93\x5f\xf7\x95\xe8\x98\xa6\x32\xeb\xe3\x4f\x34\xef\xeb\x6f\xfd\x0a\x33\xfc\xb9\x3c\x38\xd7\xec\xae\x1f\xcf\x78\x31\x3a\x2f\x2b\xa3\xc3\xc3\x55\x05\xd2\xe9\x1a\x70\x11\xae\xd1\x10\xc2\x78\xdc\x08\xe3\x71\x9b\xa6\x32\x2e\x85\xef\x6f\xca\x68\xbe\x71\xee\x1b\xf9\x35\x43\xe7\x7d\xd8\xd2\x21\x28\x05\x83\xea\x5d\xd7\xb5\x82\xb1\x3a\x21\x6d\x2c\x9d\x0a\x16\xe7\xff\xf9\xbf\x73\x59\x57\x61\x74\x19\x6e\xd4\xca\x58\xb8\x31\x5a\x2c\x5d\xee\xd8\x49\x9c\x26\x4c\xcf\xb4\x65\x5d\x86\xae\x01\x1f\x33\x7a\xc3\x96\xc1\xc3\x70\xa3\x4a\x18\x87\x1b\xcd\x9a\x28\xdc\x38\xe7\x06\xe1\xc6\x19\x1b\x2c\x93\x1a\x8c\xd3\x15\x6d\x4a\xfe\x37\x32\xcb\xa7\x25\x66\xe1\x7f\x93\x51\x3e\xfd\x36\xa3\x8c\x37\x77\x67\x7f\x33\xa3\xdc\x6c\x1e\xab\xed\x70\x63\x98\xc8\x64\x33\x23\x8c\x36\x23\x1f\x86\x1b\x4d\xcc\x69\xb8\xd9\x6e\x99\x85\xff\x6b\xbd\xb5\x35\x1b\xeb\xa1\x45\xca\x5d\x58\xf7\x6d\xec\xd4\x5d\x1b\xb7\xeb\xd8\xb1\x4f\x25\xab\xe8\x80\x35\x3d\xbd\xb4\xf7\xc3\x62\x5d\xd0\x87\xe1\xfa\x03\x48\x23\xe4\x69\x7b\x39\xc6\xab\x54\xd3\x90\x8e\x99\x52\xc2\xbe\x37\x26\x31\x97\xa3\x1c\x35\x12\x44\x82\x0d\x27\xe2\x99\x81\x68\x8f\x74\x3e\x9f\x55\xb3\x62\x2a\xd8\x4d\x5b\x03\x35\xfa\xed\xc1\x98\xdd\x66\xcb\xb6\x61\xd8\xa7\x37\x45\x91\xd3\x9b\x62\x89\x17\x22\x9e\x39\x6b\xb5\x0d\xca\x87\x63\xd6\x1e\xb3\x81\x54\xbf\x76\x6f\x1b\x61\x2a\x92\x58\xb4\xa7\x71\x64\x10\x6b\xed\xe3\x32\x17\xb1\x25\x29\x86\x54\xd5\x65\x75\x52\x8a\xae\xbb\x52\xb6\x8d\xd9\xd9\xca\x42\x83\x5e\xdd\xc0\x49\xa6\xcc\xfc\xc6\xde\x96\xf3\x9a\xf2\x54\x69\xaf\x55\x2e\x72\x9e\xb3\x40\x58\xef\x73\x6e\x72\xde\x52\x11\x8e\x9c\x2a\x4b\x39\x47\x53\x11\x8d\x9d\x2a\x5f\x39\x6f\x69\x5e\x78\xbf\xa8\x2b\xe5\xcc\xa9\x1a\xf9\xce\xeb\x74\x9c\xc3\x3d\x2c\xf0\xa5\xc3\x34\x91\x4e\xd5\x7f\xee\x9c\xb1\xa9\x64\x93\x80\x09\xa7\xea\x48\x77\x4e\x43\x19\x97\xaf\x0b\x7f\xba\x73\x12\xdf\x64\xf0\x55\x8e\x76\x9e\xb1\xd0\x7c\xb0\xb6\xc8\x04\x5e\xee\x7f\xae\x99\x75\x1d\x2b\x5c\xfd\xa7\x59\x41\x1b\x44\xbf\xe6\x85\x4b\x33\xa0\x67\x37\x3a\x4f\x45\x65\x8a\x5c\x57\x27\x59\x2c\xc0\x99\xd0\x5b\x73\xa4\xcc\x81\x7a\xfc\xe9\x51\x58\xf1\x61\xbd\xee\xe9\x46\x9e\xd4\x39\x7f\x12\xf7\xe9\xb8\xa1\x4c\x9c\x46\x32\x52\xad\xc8\xac\xa7\x7e\x94\x4c\xc7\xf4\xce\x51\x0b\x50\x1c\x5e\xaf\x9a\x34\xba\x68\xbb\x1f\xd1\x71\x3c\x6c\xd8\x3f\xb2\x1e\x2b\xa7\xfb\x72\xa9\xd0\xa4\xd4\x5a\x0f\x50\x9f\xab\xe5\xd2\x12\x8e\xe3\x84\x35\x26\xf9\x12\xa7\x46\x65\x18\xa2\xed\x1b\x7b\x35\xb9\x75\x56\x4f\x2d\x85\xd9\x64\x37\xce\xf1\x7e\x1a\xc3\x34\x04\x1d\x67\x72\x53\x01\xd6\x56\x7c\x43\xd1\x49\x23\x5e\x52\xa2\xe5\x54\x05\x70\x2a\xdb\x7b\x0d\x25\x64\xae\xd2\x44\x46\x83\xbb\xbc\x6d\xb5\x79\x3b\x43\x27\x6a\x4c\x3d\x55\x58\x3f\x75\xf2\xe1\x5e\x43\xe7\x20\x8e\xe5\xea\x1e\x98\x8c\xdb\x3b\x8d\xfa\x0a\x9b\xa4\x61\xc8\x92\x44\x2d\xeb\x1b\x3a\xe6\x29\xe5\xa1\x31\x46\xab\xeb\x75\x05\xe5\x54\x44\x93\xc2\xb8\x1d\x86\x68\x52\x41\x71\xc6\x64\xe3\x19\x95\xec\xc1\x79\x34\x61\xd6\xa2\xbd\xbe\xc3\x69\x78\xdd\x17\xf1\xd4\xe6\xb2\x9c\xe3\xfd\x1c\xdc\x70\x5d\x38\x8e\xa6\x0e\x38\x82\x85\x12\x79\xfa\x1a\x07\x0f\x17\x2c\x39\x8d\x93\x48\x5f\xf1\x08\xce\x20\xba\xdd\xc0\x5d\xba\xa2\xdc\xbe\xfb\x05\x3d\x25\x29\x96\x77\x78\xf3\xca\x7e\xb5\x59\x87\x7b\xba\x59\xab\x78\xb5\x59\x2f\x38\x5d\x9e\xe4\x22\x9e\x25\xcb\xf3\xfb\xfb\x66\x3c\x1f\x42\x3b\x0a\xe4\xa9\xd4\x27\x6f\x9e\xa1\x0b\xcb\x5a\x76\x40\x6f\x33\x38\xac\x1f\x49\x47\x0d\x9d\x82\xfc\x5b\xbe\x02\x61\xb1\xc5\xb1\xc2\xa2\xfa\xb1\x8c\xcf\x0c\xde\xbb\xc1\xbb\x9e\xf0\xff\x26\xd6\x19\x8a\xb6\x15\x69\x57\x66\x3b\xc3\xaa\xe3\x03\x33\x77\x07\xd4\xbc\x59\x5f\xac\xb6\xea\x90\x02\x51\x86\x14\x08\xdb\x79\xf8\x54\xc2\x96\x32\x3a\x9b\x4d\xd1\x73\x88\xe3\xab\xe7\xf9\x5c\xf4\xca\x77\xff\xe1\xf8\xce\x96\xfe\x43\x74\x77\x99\xd8\x2b\x37\xf8\x52\xa9\xf0\x7c\x73\x85\x20\xc8\x4b\x86\xee\x68\xcd\x2f\x6b\xa2\x19\xf2\xba\xbc\xa5\xda\xab\x61\x0d\x56\x24\xe5\x0c\x7d\xbc\x81\x5b\x9d\x1a\x58\x37\xd5\x76\x06\x87\x99\xe7\xb4\x9a\x45\xa4\xf1\x7f\xce\xb4\x2a\xd3\x99\xb8\x41\x6c\xf6\xb4\xdc\xe0\x91\xde\xd5\xa2\x2e\xdd\xd5\xee\x06\xea\x86\x3b\x15\x15\xef\xff\xb3\xcb\xd4\x60\xbb\xfa\x5d\xe7\xc2\x77\x36\x59\x4a\x7a\x39\x33\xa2\x56\xac\xb4\x87\x7e\xb1\x84\xc9\xdf\x59\x3d\xd8\x7f\x41\x44\x5b\xdb\x07\x9b\xad\xad\x37\xab\x4c\x96\x42\xb9\xcc\xc2\x8a\x6b\xaa\xe5\x94\xf1\x7e\xc4\x87\x4b\xda\x1a\xbb\x9d\xea\xed\x59\xfb\xb8\x61\x55\x32\x0e\xfb\xcb\x5c\x52\x8e\xc3\x68\xbb\xfe\x4e\x75\xea\x09\x9d\x30\xbf\x61\x56\x3f\xbd\xbf\x10\x4c\x96\x3a\xe4\x57\x38\x8e\xfa\x7d\xc1\x92\xa4\x82\x86\xbe\x58\x32\x5c\x3f\x87\x15\x3f\xd7\xc4\xf8\xb9\xde\x9b\xdd\xdc\x1f\x5d\xdb\x67\x98\x35\x63\xb6\x6d\x9e\xf4\x32\x3d\x4e\x13\xc9\x44\xe3\x4c\xa7\x7f\x35\x35\x59\xfb\xf8\x3a\x15\x87\xbd\x53\xe2\x38\xd9\x1d\xfd\xa4\x22\xef\xca\x56\x0d\x62\x31\xc9\xec\xfe\x8a\xae\x5a\xb6\x31\x8c\xc7\xed\x64\x52\x71\x52\x9a\xfe\x72\x96\xba\x28\x03\xed\x78\x75\xc6\x56\x3d\x80\xaa\xb0\xff\xb9\x8a\x4d\xbb\x7f\xa7\xea\xdc\xeb\x8a\x38\x31\x01\x98\x01\xed\x0f\x99\x03\x5b\x5e\xa5\xc7\xd6\x47\x3e\x98\x02\xb9\xfa\xe4\xac\x0c\x83\xc8\x60\xf2\xed\xb9\xd5\xc1\x0f\x19\x50\xe6\xe9\xd0\x3e\xc7\x05\x52\x54\xfe\x18\x67\x7b\xbb\x79\xdc\x2c\x53\x06\xea\x78\x00\x27\x69\x16\x2b\x57\x34\xfc\x77\x8c\x37\xc1\x68\x7f\xc9\x74\x4b\x98\x54\xeb\xe9\xf2\x44\xea\x47\x09\x0d\xc6\x7a\x26\x21\x69\x0b\x81\x2a\x3b\xb1\x35\xec\xc4\xfe\x95\xec\xf4\x8e\x31\x51\x0e\x6a\xd4\x5f\x3d\xa8\xba\x8b\x9e\x85\xc0\x73\x7e\xaa\xee\x9f\x2d\x79\x1a\xb2\xe9\x93\xdc\x94\xd3\xc7\x9e\x36\xff\x75\xb2\x3f\x4e\x65\xf4\xdb\xf3\xe0\x2a\x51\x62\xe5\x73\xd1\xcd\x4a\x0e\xb8\xf4\x3d\xce\x02\xb9\xbf\xc1\xba\x29\xff\x89\x89\x44\xeb\x87\xdc\xc4\x1d\xa9\x15\xf9\x5f\xd4\x80\x27\x82\xf2\x70\xf4\x9b\x0d\x10\x2e\x7d\xbb\x6a\xa1\xf8\x4f\x56\x9d\x46\xe3\xbe\xb2\x16\x7e\xbf\xf6\x93\x7f\x71\xed\x1f\x13\x26\x7e\xbf\xf6\xd3\x7f\x5d\xed\x2f\xe2\x6c\x4c\x7f\xbf\xf6\x47\xff\xba\xda\x3f\xb0\x9b\xe8\x6f\x55\x1e\x3c\xfb\xd7\x55\xfe\x77\x1b\x1e\x7c\xb5\xdd\x1f\xda\x1a\xa7\xe7\x6e\x30\x05\x7b\x86\x57\x16\xc8\x98\x0f\xa2\x61\x8e\xfe\xb6\x20\x66\xda\xde\x2b\x37\x80\x69\x78\xad\x28\xe7\x7d\x07\x9c\x7f\x1b\x3c\x1c\x3c\x1c\x3c\x2e\x3e\x0e\x62\x2e\xdb\x03\x3a\x89\xc6\x4a\x79\x9c\xc4\x3c\x4e\xa6\x34\x64\x65\x03\xef\xca\xda\xb8\x45\xdc\xe5\xf2\x51\x89\xd7\xb6\xeb\xd2\x1c\x14\x22\xdc\x0d\x3f\xe6\x31\x36\xb4\x88\xb1\x29\xa2\x5c\x66\xe8\xcf\x31\xfc\x0c\xc1\xd8\x48\x1f\xea\x57\x82\xad\xdc\x2a\xfb\xd3\x28\xcf\xaf\x8c\xea\xfc\x54\x07\x84\x05\xaf\x96\x03\x79\x76\x7d\x93\xc7\x47\xd8\x69\x65\xa6\xdb\xc0\x40\x02\x85\xad\xad\xb4\xb8\x81\xbb\xba\xcc\xbd\x58\x0a\xb4\x39\xa7\xe6\x34\xf9\x02\x71\x37\xfc\x56\xbf\xb8\x7b\x86\x82\x1b\xd5\x80\x5d\xa0\x2e\xad\xdf\x0e\x28\x8d\x4d\x14\x7e\xc5\x2e\xfd\x6e\x4e\xad\x9e\x83\xbe\xb9\xea\xd6\x44\x58\xbf\x82\x35\x8a\x7e\xa0\x46\x30\x1f\x84\x57\x7d\xeb\xfd\x8e\x83\xe1\xdb\x4d\x7e\x4e\xae\x1d\x50\xd1\x2e\x82\xfe\x4a\xd6\x7b\x9e\x9d\xa2\x33\x9c\xf1\x69\x6c\x4e\xc1\xdc\x51\x78\xc9\x34\x27\xf6\xe1\x3e\xfc\xac\x4f\xdf\x98\xe5\x10\xee\x90\xdc\x86\x9b\x6d\x9d\x22\x09\x6e\x11\xdb\x86\x64\x1b\xcc\xbd\xa5\x97\x18\xd7\x1c\xe9\x1a\xe3\x37\x06\xb7\x48\x6c\xc3\xb1\xd4\x99\x5d\xb8\x1b\x46\xea\xcf\x17\x5c\x8f\x94\xac\x40\xdf\x4a\xa4\x3a\x0a\xde\x8e\xc1\x71\x2a\xf0\x0f\xd7\x0f\xc1\xf8\xc6\xce\x6b\x51\x5d\xfb\x8e\x0b\xae\xe7\xf4\x26\x50\xcb\xb5\xfe\xa7\x2d\xe3\xe1\x70\xcc\xd4\xaa\xdf\x9e\xf4\xf3\x97\x63\xed\x7e\x2c\xa2\x19\x26\x41\x7b\xbf\x31\x95\xed\xdd\xc6\x34\x68\xef\xd6\x63\x26\x82\x58\xca\x78\xe2\x80\xd3\x99\xde\x36\x92\x78\x1c\xf5\x1b\x62\x18\x50\xe4\x41\xc3\xfc\xe7\x76\x76\xf6\x71\x39\x4c\xd7\x96\x30\xa8\xf9\xcb\x6c\xdb\x3f\x23\x25\x10\x94\xf7\xf3\xbd\xfb\x8a\x6a\x3d\x66\x42\x4e\x28\xa7\xc3\x72\x00\xa3\x7a\x69\x4e\x6f\x4a\x35\xe1\x74\x1b\x71\x0c\xdf\xb7\xf1\x2a\x65\xaf\xcc\x6b\xb6\xe3\x57\x47\x31\x53\x71\x6a\x7d\xbd\x24\xf6\x22\x3e\x8e\xb8\xe5\x6a\x5c\x6e\xd1\x9a\x6d\xb2\x5a\x54\x02\x67\xb3\x8a\x56\xcd\x66\x0d\x3b\xf2\x41\xe9\x37\x46\xcd\xa9\x68\x3a\x2f\x6b\x7e\xa4\xba\xb9\xf5\xbe\xf6\xbd\xbe\x89\xfa\xa3\xf6\xbd\xbe\x7f\xf5\xd6\xe6\xa6\xaf\x1c\x45\xa2\xea\x5a\x78\x12\x56\x12\xea\x54\x26\x6b\xf6\x74\xbe\x0d\x3a\xf6\x2d\x7c\x8e\x5b\xce\x38\x0a\x1e\x04\x71\x2c\x13\x29\xe8\xb4\xbd\xe7\x7a\xae\xd7\xa6\xe3\xe9\x88\xba\x07\xed\x7e\x94\xc8\x07\x61\x92\x94\x00\xee\x24\xe2\x6e\xa8\x14\xee\x97\xa1\x1a\xcc\xf3\x6d\xe0\x06\x87\x96\xcc\x74\xc6\x92\x78\xc2\xda\x7b\xee\x43\xd7\xd3\x25\xed\xd7\x65\xe1\x1f\xb5\xc2\x6c\x3c\x69\xf7\xa9\x64\xd3\x28\xbc\x66\x42\x17\xac\xbe\x32\xc5\xde\x87\x75\x1d\xd8\xa8\xbb\xdf\xd5\x5a\xf4\x18\x84\x1b\xde\xa8\x3f\x63\xdc\x2d\xb2\xbc\xde\x8b\xe2\x49\x2e\x65\x7e\xa5\x96\xf4\x2d\x5e\x06\xab\x5e\x86\xd6\xcb\xa5\xbe\xfd\x16\x22\xe1\x86\x1f\xeb\x2b\x66\x36\xa5\xd4\x54\x2d\x64\xe3\xeb\x50\xbb\x0b\x4a\x11\xb5\xe3\xeb\xb4\xfa\x0d\x51\xb0\xb5\xf9\x2d\x17\x95\xcf\xbc\xf8\x1c\x0d\xd0\x8e\x76\x1a\x29\x92\xf2\xb2\xb5\x32\x65\x3a\xa5\x6d\x93\x51\x5c\x49\xfa\x25\x04\x41\x81\x40\x1f\x2d\x5d\x8f\xb5\x32\xfd\x16\x75\xe4\xa1\x95\xb9\xa4\x78\x19\xe8\xab\x3b\x8a\x65\xd7\xa4\x4c\x7f\x1e\xc2\xbb\x10\x5e\x84\xf0\x29\x84\xaf\x21\xfc\x19\x02\x8f\x41\xc4\x20\x63\xf2\x99\x23\xe7\x9c\x26\xd7\x0e\x06\x16\xaf\x4b\x8e\x24\x63\x54\xe4\x47\xca\xd2\x28\xd5\xef\x02\xd2\x6c\x7d\xa2\x97\xac\xf0\x14\x2a\x37\x94\xe9\x6b\x3a\xd0\x17\xa1\x6f\x1b\x2b\x4e\x0a\x09\x74\x4f\xad\x3b\x6d\x98\x75\x97\x15\x25\x0c\x3e\x8a\x55\x17\x07\xc5\xd3\x44\x52\xc9\x1c\x90\x18\xfe\xe3\xa3\x70\x39\xbd\x89\x86\x54\xc6\xc2\x4d\x13\x26\x8e\x86\x8c\xcb\xf2\x12\x9b\x73\x11\xf5\xb5\x33\xaa\xd9\x5c\x89\x6d\x44\x93\x51\x1e\x2e\x24\xf1\xea\xe3\x4e\x5d\xe1\x86\x52\x8c\xff\x64\x77\xf3\xb9\x70\x27\x4c\xd2\xec\x31\x19\x45\x03\xa9\x9f\x3b\x87\x6a\x7d\x4e\xa5\x8c\xf9\x7c\xce\x5d\x49\xc5\x90\x49\x7d\x44\x38\x9e\xf1\x71\x4c\xfb\xf3\x39\x12\xee\x54\xe8\x6b\x76\x9f\x19\x5e\x40\x58\x2b\x27\x23\xc1\x06\x20\x88\xea\x1a\xe0\xe4\x8c\x21\xa9\x8f\x98\xa0\x14\xf1\x66\x53\xb8\xc1\xcc\xb0\x8b\xbe\xbc\x32\x08\xcc\x8f\x40\xff\x48\x5c\x6a\x7e\x26\x2e\xed\x15\xee\x6c\x3f\xf3\x9f\xcb\x85\x39\x33\x01\xe1\x91\xbf\x32\x2e\x4d\x5f\x9a\xc9\x41\x57\x2c\x15\xdc\x43\xdf\x5c\x8a\xb9\xef\xeb\xab\x34\x43\x4f\xfd\xeb\x29\x14\x69\x9c\x25\x31\xa7\xfa\x61\x77\x01\x61\x4c\xc6\x1c\xe2\x98\x50\x0e\x91\x7e\xe9\x2d\x60\xa0\x1f\xda\x3b\x0b\x08\x62\x32\x88\x21\x89\x49\x10\xc3\x78\x1d\x4b\xdd\xd3\x67\x7e\x12\x03\x3d\xd6\x11\xd9\x2f\xfd\x28\x06\xfa\x4a\xfd\x0d\x63\x5f\x00\xfd\xee\xbf\xd1\xa9\xbd\xe8\x63\x3f\xcb\xa8\x45\xbf\xf9\x8e\x03\xa1\xf4\x4f\x80\xee\xe8\x23\xc1\xc7\x3e\x87\xf0\x85\xc2\x12\x5c\xfb\x27\x10\x8c\x15\xaa\xe0\xa9\x56\x55\xf4\xc7\xe0\xce\xbf\xcf\x8a\xe9\x9f\x1a\xea\xa7\xfa\xf3\x54\xe7\xe8\x7a\xa9\x0b\xe8\xb0\x7d\x08\xce\xfd\xec\xea\xf9\xac\x3d\xdb\x31\xb9\xa7\x67\xfe\x33\xa6\xa6\x1e\xd0\x8f\xf9\xd3\x8d\x7f\x4f\x23\x4d\xf4\x95\xfe\x1b\xeb\xbf\x3f\xf4\xdf\x3b\xfd\xf7\xa7\xce\xb7\x97\x14\x45\x3f\xe7\x4f\x41\xa8\x2b\x3c\xcd\x7f\x9b\x9a\x27\x31\xb9\x0f\x3e\xf8\x51\xbc\x80\x51\xfc\x1b\xc9\x39\x3d\x68\x67\x49\x36\x87\x31\x61\x1c\xa6\x8a\xd0\xa1\x6a\xd0\x77\x8d\xfe\x56\xfd\xfd\xa0\xfe\x9c\xa9\x3f\xe7\xea\xcf\x4b\x4d\xd2\x4c\xb7\xed\x60\x01\x77\xfa\x61\x67\x01\xb7\xf9\x90\x1e\xc7\xeb\xf3\xe6\x1f\xd8\x79\xf3\xaf\x73\x6e\x38\xca\x91\x9d\xc5\x1b\xee\xc5\x43\x1c\x49\x2d\x31\xae\x62\xb2\x32\xed\xdc\xf2\x6d\x98\x1c\xdf\x4b\x71\x77\xff\x51\x14\x97\x7f\x12\x51\xde\xb9\x63\xdf\x09\x2a\x98\x9a\x5d\x48\x9f\xa0\xc1\x78\x01\x4f\x63\xf2\x9a\xc3\xab\x98\xfc\xe4\x70\x1a\x93\x57\xb1\xe2\xa0\xef\x31\x39\x17\xf0\x61\x3d\x91\xf7\xf4\x95\x2f\x21\x18\xa9\x36\xde\x9a\x46\x7e\x59\x3b\x0e\xc2\x0d\x7a\x3a\x01\x5d\x68\x92\xe2\xe9\x44\x35\xe7\xeb\xc1\x4d\xee\x3a\x5e\xe4\xad\xfb\x12\xc3\x89\x19\xbc\xd7\x9c\xc4\x2b\xd3\xbe\x42\x08\x31\x44\x25\x75\xaf\x7d\xa9\x78\x28\x06\xea\xf9\x29\xd0\x03\x5f\x64\xc4\xfe\xf4\x99\x62\x26\x0a\xc1\x7b\x3f\x82\xe0\x93\xaf\x33\x4f\x9f\xaf\xbf\x25\xf0\x3e\xe8\xab\x96\xbe\x55\x18\xde\x29\xd5\x06\xc3\x49\xbc\x3a\x01\xee\x43\x08\x74\x02\xdc\x8f\x31\x19\x30\x14\x61\x88\x36\x25\xef\xfb\x18\xc3\x0c\xc5\x26\xfb\x97\x49\x8b\xf8\x26\x26\x31\x87\x67\xf1\xe6\xfb\x1f\x62\x4e\x66\xe8\x4d\xbc\xe1\x78\xb1\x93\xf2\xa9\x88\x43\x96\x24\xac\xef\xe4\xab\x6b\xc0\x50\xe6\x73\xcc\x9d\xe4\xd6\x97\xec\xf4\x95\x93\xa4\xd3\xa9\x58\x2a\xb7\xb3\xa4\xc4\x3e\x8b\x91\xf3\x91\x5f\xf3\x78\xc6\x1b\xf2\x6e\xca\xfc\x86\xd3\xe2\x78\xa1\x66\x8b\xee\xcc\x3b\x14\x41\x99\x04\xe4\xc9\x9d\x03\x27\x31\x52\xdf\xf4\x87\x3c\x7d\xc8\xd2\x7b\xb3\x4a\xc5\x1c\x02\x86\xce\x85\xce\x05\xf2\x39\x36\xc8\xcc\x89\xf7\x59\xac\x3e\xad\xe8\x9e\x60\xa2\x87\x06\xc3\xcf\xf8\x37\xef\xb2\x78\xbd\x81\xb9\x6b\xa9\xc6\x75\x9a\xf1\xb8\x7a\xc5\x1f\x2f\x52\xeb\xae\x4f\x3e\x46\xb3\x3b\xd7\xb2\x63\x1c\xd8\xce\xfd\x96\x1d\xca\xc9\x2e\x11\xd5\x31\xc9\x5a\x19\x00\x4e\x52\xa5\x1e\x62\xab\xac\x36\x31\xf2\xdc\xf9\x96\xa7\xf4\x67\x0c\x72\x3e\x67\x26\x4c\xba\xf2\x4d\xe7\x57\xca\xbf\x29\xa5\x47\x4d\x76\x78\x19\x93\x6f\x31\xbc\xff\xdd\x1e\xfa\x11\x6f\x4a\xc7\x6e\x12\x37\x0d\xd5\x74\x92\x26\x65\x93\x9e\x1b\x6f\xf3\xa5\xe0\x49\xbc\x3e\x69\xe4\xfb\x18\xde\xc6\x70\x8b\x7e\xc4\x56\xfe\x29\xad\x9c\x69\xb1\xf7\x3c\x26\xe8\x79\xa8\x45\xa6\xb7\x32\x7b\x9e\x49\x61\xa7\xcc\x5c\xd5\xf4\x5e\x9e\x09\xcf\x53\xb2\xa5\x96\x6d\xea\xb9\x41\xf9\x2e\x26\x3f\x05\xbc\x88\x7f\x91\xc6\xdb\x0c\xa9\xce\x6f\xa5\xbe\xa6\x4a\x11\xd5\x29\xf3\x28\xb4\x3b\x45\x82\x5b\x5d\xdf\x11\x4a\x75\xca\x86\x43\x2f\x4b\x63\xc5\x20\xf4\x53\x9d\xc6\x2a\xd5\x69\xac\x84\xea\x13\x09\xd4\x4f\x5d\xba\xc0\xdd\x94\x20\x46\x34\xa2\x1d\xdc\x43\x59\xaa\xef\x56\x07\x24\x91\xad\x0e\x74\xb0\x9f\xbd\xa3\x26\xf7\x77\xab\x83\x21\xd5\xa3\xf6\x53\xac\x5a\x04\x56\xf4\x4a\x82\x5e\xc4\x46\x9b\xb5\xb3\x7a\xa9\x59\xf9\x49\xb7\xfe\xeb\x7f\x37\x0b\x07\xda\x05\x13\x56\x98\xd0\x04\xdb\xa7\x60\x52\x64\x2b\x10\x4d\x1e\xd5\xe9\x66\x98\x6e\xe0\x9f\xf1\xea\x3c\xbe\x5f\x63\xb8\xd1\xb7\x4e\x00\x8f\xc8\x13\x10\x11\x09\x53\x90\xd1\x2a\x60\x4f\x1f\xdf\x34\x41\x4a\xcd\xe6\xd6\x83\x8b\xbf\x92\xdb\x20\xbe\x7c\x60\x0e\x0e\x71\x7d\x55\x1f\x69\x71\x4c\x08\xd7\x79\xa1\x4c\x76\x5f\x16\x91\x55\x09\x12\x1f\x1f\x9a\x24\x85\xab\xd2\x1b\x52\xd9\x98\xc4\x89\x6c\x3c\xde\x98\xdd\x30\xdb\x8d\x96\x11\x72\x3c\x57\x49\xc6\x75\xc9\x15\x07\xe3\x98\xca\x5a\x6a\x45\x1e\xa1\x0e\xdb\xfd\x43\xe8\x93\xfd\x76\x96\x44\x48\x23\x92\x4a\xa0\xd1\x2f\x52\x9f\x37\xd2\x08\xf1\xd6\x81\xf7\x87\xf8\xe3\xc0\xfb\xa3\xc3\x76\xd5\x33\x92\x6d\x8a\xf5\x0f\x85\x9c\xb5\xf4\x25\x66\x61\x65\x81\xa2\xe5\x4d\x50\x21\xe1\x10\x13\xb1\x9e\x2f\xc2\xbf\x27\xda\x4c\x42\x39\xb5\x78\x0b\x37\x5c\x96\x6b\xe9\x2a\xb9\x96\x1a\xb9\x66\xf2\x3d\x6a\x37\x5f\x5d\xba\xa5\x30\x43\x14\x8c\xfc\x33\xf7\x5c\x43\x1c\xad\xbf\xd5\x26\x8c\x34\x3f\x19\x4d\x22\x8a\x48\x1c\xc1\x60\x33\xf8\xf3\x02\x3c\x88\x96\x32\x16\x67\x02\x79\x7d\x1f\xb1\xac\x8f\xd6\xf6\x0f\x5f\x39\x5b\xa4\x16\xff\x7a\xe2\x62\x48\x22\x12\x44\x30\x8e\x7e\xf3\x26\xa7\x7e\x44\x3e\x0b\xb8\x51\x73\x04\xb6\x23\xf2\x1e\x26\x11\xb9\x86\xcf\x62\x99\xcf\x8b\xe5\xc4\x78\x78\x8d\x33\xd9\xe4\x85\x2f\xae\x31\x48\x52\x44\xad\xcb\xdb\x44\xd9\xb4\xdd\xce\xfe\xee\x01\x3b\xf8\x03\xb1\x76\xe7\xf1\x43\x4f\xd9\x65\xd9\x49\x7a\x94\x1e\xee\xce\xe7\x5b\xe3\x14\x31\xdc\xa3\xed\x8e\x4f\x71\x0b\xf5\xd5\xaf\x76\x3f\x45\x1a\xb8\x0c\x39\x51\xdc\xde\x12\x2d\x89\x17\x99\x02\x93\xd6\x33\x29\xec\x76\x0e\x69\x4f\xd3\xe1\x8b\x5c\x7f\xb1\x2e\x08\x78\x7c\x48\xe7\xf3\x9d\xc7\x84\x10\xda\x6c\x66\x95\xe6\xd0\x3b\x07\x0f\x1f\xed\xb1\xfd\xba\x6f\xb5\x82\x71\xdf\x7b\xfc\xf0\xa0\x80\x29\xf3\x31\x78\x16\xcc\xc3\x87\x0f\x0f\xd8\x41\xdd\x79\x5e\x41\xd3\xf1\x76\x0f\x1e\x15\x30\x07\x2b\xd1\x74\x76\xbd\xbd\x83\x92\x9e\x87\xab\x11\xed\x1f\xec\x5a\x44\x3f\x5a\x0d\xf4\x68\xb7\x73\xf0\xa8\x00\x7a\xbc\xb2\xba\x1d\xef\xf1\xe3\xfd\x9d\x02\xa8\x4c\x05\x51\x41\xb5\xb3\xbb\xff\xe8\xa1\x05\xd5\x59\x8d\xeb\x60\xe7\x60\xbf\xec\xa6\xce\xce\x6a\x5c\x8f\x1e\xed\x9b\xce\xac\x29\x8b\xb6\xc0\xd3\x21\xaf\x5a\xe0\x5d\x49\x94\x9a\x44\x79\x4a\x6d\x44\x83\xc8\xfa\x23\x22\xd4\x47\xdf\xf3\xf4\x81\x71\x8a\xf6\x30\x04\x29\x72\xda\x0e\xb6\x5e\xee\xd8\x2f\xf5\x6f\x8c\x61\xb4\x61\xaa\xec\x54\x2e\x3d\x8b\x7e\xff\x82\xaf\x5c\xa7\x10\xd9\xcd\xae\x3a\xdd\x9b\x9a\x33\xc8\x03\xe9\xd2\x5c\x57\xdb\xb2\xae\x22\x60\x44\x5f\x4f\x84\x18\xa1\xd8\x2d\xae\x58\x60\xd9\x1d\x1f\x33\x34\x8a\x40\xe8\xfb\x5d\x41\x9a\xab\x3d\xa6\x11\xb9\x49\x61\xb6\xc1\x64\xe0\x7f\x20\x25\xd4\x5b\xda\x56\xb8\x5b\xb1\x76\xd5\x72\x3c\x56\xba\xd4\xfe\x63\x52\x32\x52\x93\x43\x46\x75\xe1\xb9\xb3\xdc\xad\xfe\xaa\xbe\xf6\xad\xbe\x86\x4a\x3d\x06\x67\x2a\x0d\x9c\xab\x10\xb2\x08\xab\x77\x9e\xd9\x6e\xcb\xa1\x93\x68\x4d\xce\x72\x55\xee\x9b\x21\xa4\xce\x0c\xb3\xe8\x57\xe5\x3b\xa6\x7c\xcb\x94\x5f\x09\xd3\xce\x60\x14\xbf\x5c\xfe\xa2\x6d\xe5\x77\x11\xa1\x01\xa2\x11\x70\xf0\xf2\xff\x63\xa5\xa1\x9a\xf3\xbf\x9f\x05\x86\xdb\x68\x83\x95\xac\x94\xe4\x8a\x7e\x7c\x1c\xfd\xad\x2b\xbe\x8a\x1b\xe6\xac\x1b\xb4\x74\x8c\x8f\x39\xb1\xac\x59\x29\x94\xfa\xb2\x04\xfb\xa6\xac\x7c\x06\xd6\x41\x8f\xa3\x3a\xa8\x76\x4f\xac\x98\x33\x84\x23\x45\x7d\x07\x42\xff\x04\xfa\x7e\x07\x02\xdf\x53\x8d\x50\x16\x82\x95\x67\x45\x29\x34\xdb\x12\x69\xcc\x6a\x89\x3f\xc1\x3a\x73\x88\x5a\xc1\x16\x18\x8e\x56\x21\x9e\xa1\xeb\x48\x2f\xab\x4b\x38\xbe\x33\xd8\x4e\x41\x2b\x3e\x06\x09\xd5\x57\xd7\x2f\x9b\xbb\x66\x11\xd2\x09\x53\x6c\x24\xca\x2a\x2d\xf3\x25\xcb\xcc\x2a\xf5\x03\x66\x50\x69\xe3\xf4\x2c\x5a\x63\x02\x14\x52\xa2\xdd\xa9\x5f\x33\x05\xcc\xdc\x18\x73\x15\xad\xbf\xf2\x44\x67\x3a\x4c\xdd\xed\xf9\x5c\x19\x0d\xc5\x1b\xa6\xde\x30\x97\x66\x19\x12\xb3\x64\x92\x26\x95\xa4\x9d\x5a\xb0\x44\x96\xdd\x8f\xc2\x74\x22\x49\xb6\x94\x81\x90\x69\x15\xba\xc8\x40\x98\xa7\x78\xa4\x6e\x1f\xa8\x95\x7b\x50\x61\x0b\x21\xcd\x52\x1f\xc6\x44\xd9\x2a\x11\x49\x75\x8e\xca\x54\xdf\xab\x99\xba\xac\x5b\xa7\xb2\x46\x52\x0c\x51\x91\x62\x51\x53\x47\x71\x4e\x60\x58\x23\x4b\x7d\xcf\x93\x47\x66\x14\x16\x2d\x28\x88\x52\xf8\xa8\x26\x0a\xc3\xd3\x88\x3c\x85\x57\xd1\xea\x7b\x4d\xea\x37\x82\x66\x95\x28\x80\x41\x0c\x83\x18\x17\x17\x2e\xd2\x42\x14\x4b\x9d\xb8\x51\xea\xc4\x8d\xd2\x65\xdd\x22\x47\xd3\x53\xd5\x94\x14\xd7\xa7\x54\x82\xae\xa2\xcc\x77\x74\x87\x5e\x99\x11\x08\x31\xc4\xf5\xb8\x2c\x5d\x77\x96\x10\x53\x7d\xad\x2d\x6e\x16\x9a\xb0\x44\x14\x63\xad\xbd\x9d\xae\x6a\x9f\x24\x05\x98\xb9\xa0\x45\x0f\x41\x7e\x26\xb5\xbc\xf1\xb1\x9a\xf6\x32\xcf\x3c\xa9\x1a\x28\x5d\x7d\x2b\xcc\xf7\x68\x8d\xa3\x68\x27\xf3\x43\x5d\xaf\xb6\xab\x22\x06\xa3\x14\xbe\x47\xe6\xf6\x8b\x0f\x6b\xb0\x3c\x86\x50\x23\xf9\xb2\xae\x96\x7d\x18\x6a\x80\xcf\x62\x55\x35\x5f\xb4\xb8\xfe\x10\xa1\x63\x89\xcd\x49\xd4\x5b\xa5\x35\x6b\xa9\x79\x1e\x29\xdb\x7e\x7f\x01\x27\x95\xfe\xa9\xf8\x17\x1a\x4b\x93\x9e\x2b\x51\xa7\x0d\xdc\x7a\xea\xdb\x80\x21\x96\xa5\x70\x80\x0c\xca\x54\x2f\xe1\x43\x84\x98\xde\x84\xe3\x56\xc4\xb8\x96\x14\x9f\x4d\x7a\x60\x2d\x1e\x74\x4a\x19\x38\x8f\x34\x63\x6e\x70\x7a\x18\xaf\xdd\x1d\x3a\x89\x72\xd7\xdd\x79\xa4\xef\xf1\xc9\xae\xb9\xfd\x18\x91\xc2\x91\x95\x26\x0e\x9c\x0b\xe3\xd8\x62\xbc\x9f\x1c\x49\x07\xde\x9b\x9f\xe9\x54\x49\xa7\xbe\xf5\x26\x91\x54\x48\x1b\x64\x10\xf1\x21\x13\x53\x11\x71\xa9\xbd\x5e\xfa\x65\x9e\x14\x37\xd1\x6e\xb3\xcf\xb9\xdb\x8c\x72\x1e\x4b\xed\xdc\x4d\x1c\xb8\xd6\xee\xb4\x5b\xf4\x14\x9c\x21\xe3\x4c\x50\x19\x8b\x8f\x1f\xde\x38\xf0\x59\xe8\x2f\xc7\xd2\x14\xd2\xe9\x02\x0a\xf8\x80\xa1\xd7\x45\x42\x3d\x8c\xe1\x4d\xd6\x10\x9d\x30\xc4\x54\xf7\x31\xc2\x55\x2a\x1c\xf8\x1c\xaf\xc1\xf5\x41\xdf\x31\x03\xcf\x56\xae\x8c\x84\xa3\xaa\xec\x97\xbe\xb9\xcc\x54\xd9\x3e\xfa\x9a\xcc\x0d\x46\xd9\x29\x83\x67\x91\xce\xb5\x61\xec\xb2\x9f\xeb\x6f\xe0\x2b\xf3\x44\x23\x63\x4b\x63\x78\xbd\xd2\x79\xc0\x78\x18\xf7\xd9\xc7\x0f\xaf\x9e\xc6\x93\x69\xcc\x99\x49\xb9\x0e\xdf\x14\xea\x53\x0c\x2f\x37\xac\xef\x7a\x8b\xe4\xd4\x1c\x4d\xd7\x6e\xc2\xf7\x51\x16\x20\x4a\xfe\xc3\x81\x1d\x9d\xad\x6f\xeb\x3f\x1c\xd8\xd5\x4f\xc4\x01\xcf\xbc\x22\x8e\x3e\x98\x03\x3f\x22\xf2\x0e\xde\x46\x2b\x59\xce\xf6\x49\xa5\x44\x22\x81\x51\x7e\xb5\xd4\x36\xbe\xa7\xf6\xd5\x52\x5a\x3f\xe5\xf3\x39\x85\x54\x2d\xbc\x66\x05\x49\x5d\x0a\xa1\x16\xfc\x4a\xd8\x6b\xdb\x2e\x2c\xe7\x8c\x36\x37\x75\x91\x50\x09\x51\x3d\x7d\xd4\x2f\x41\x42\x37\x73\x41\x19\xbd\xf4\x49\x54\xbd\x59\x47\x6e\x72\x41\xdd\xa2\xb7\x91\xb9\x93\x42\x66\x06\xec\xf3\x68\xbd\x1b\xf0\x89\x92\x82\x2b\x45\x54\x12\xc1\x59\x0a\x26\x54\x40\xbb\xef\xb4\xc4\xe8\x74\x16\xf0\xa2\x66\x88\xb3\x95\xe4\x18\x05\x41\xfb\xf1\x64\xe6\x10\xa3\xb8\x4c\x65\x2f\x56\x5d\xf0\xc0\x30\xf6\xf5\xa7\x9d\xdc\xa3\x98\x7b\xf6\x3a\xb5\x04\xf5\xdc\x0d\x5a\x1d\xad\xd1\xb9\xc1\x71\xab\x93\x67\xaa\xf7\xab\xa5\xb8\x4b\x3f\xb4\xea\x45\x45\x5e\xac\xbc\x27\x02\xc3\x27\xdd\xba\x87\x0b\xf8\xba\x41\x39\x2c\xd6\x45\x51\xb9\xef\x2c\xf7\xb1\x84\xda\xc7\xd2\xd7\x5b\xc9\xf5\xc5\x4f\xe7\x7a\xca\x97\x3f\x63\x80\xb0\x15\xb7\xb3\x96\x37\xa2\xc9\x72\x99\x33\xe0\x69\x45\x63\x5c\x60\xf8\x73\xdd\xb0\x6e\xcd\xd0\x57\xa3\xde\xb9\xdb\x0b\x0c\x7c\xb0\x7e\xf8\xff\x8c\x72\xef\x8a\x18\x90\x74\xcd\xb6\x4e\x75\x1e\xc4\x96\x6f\x36\xf3\xcc\xc6\x96\x67\x36\x77\xc3\xaa\xfe\xa6\x15\x17\xec\xa2\x1b\x12\x44\x09\xca\xbc\xb0\xf1\xaf\xbc\xb0\xb1\xed\x85\x55\x7a\x8f\xf1\xa0\xcb\x01\x59\xb6\x4e\x5e\x46\x18\xd0\xa7\x90\xdc\xd3\xaf\xfe\xa7\x08\xc2\x27\x3e\x7a\x11\x92\xfb\xf0\x89\x7f\x97\x42\x78\xa6\xf7\x5a\x4f\xfc\xbb\x74\x81\xdd\xf0\x89\x7a\xf1\x22\x74\xc3\x33\xf5\xee\x45\xe8\x06\x27\x0b\x58\xc3\xb9\x9f\xd4\xd7\x92\x7b\x75\x6b\x85\xed\x87\xae\x31\xf0\xa7\xd0\xa5\x5f\x71\xee\x76\xcb\x59\x39\x40\x62\xa0\x3e\x85\x4f\xc0\xf0\x6d\xc6\xb4\x9d\x2c\xed\x70\x5f\xbb\xdd\x7d\x0b\x4c\x94\xee\xe3\x56\x15\x0a\x14\x65\x99\x1f\x57\xd6\x66\xd5\x0c\xf1\x01\x08\x8d\xe2\x6c\x69\x6e\x65\xa4\x15\x33\xc4\x5c\x26\xa7\x8d\xba\xb5\x59\x3b\x2c\xe9\x66\xec\x30\xed\xe6\xbb\xd5\xe9\xe0\x17\x26\xd1\x3e\xa0\x77\x21\xf9\x87\xf3\x0f\x63\xf2\xe9\x10\xbc\x11\x43\x1d\x0c\xa3\x18\x75\x30\x86\x3f\x63\x54\xb9\xd0\xc0\xcb\xef\x3a\x78\x17\x1a\x03\xef\x79\x04\xef\x42\xf8\x90\x66\xcb\x1e\x5b\xcb\xad\x62\x81\x21\x1d\x6c\x74\x16\xb2\x41\xce\xce\x74\xb0\xd1\xc6\x68\xcc\x50\xaa\xba\xea\x26\x35\x16\x6d\x3a\xd0\x17\xb8\xe9\x77\x33\x14\xac\xb4\x6f\x8f\x52\x94\x5d\x2b\xaf\xd4\x67\x9d\x68\x7f\x2d\xec\x75\x8a\x3e\x4a\x94\x9a\xab\xcd\x2e\xcd\x35\x5f\xe1\x60\x93\x5a\x93\x53\xf2\xab\xba\x99\xc2\x39\x43\x71\xa4\x29\x8d\x23\x9d\xfd\x3b\x8e\xb4\xb0\xff\x35\x45\xba\x74\xa8\xaf\x9c\xb8\xd4\x44\xc5\xff\x2f\x77\x6f\xa2\xdd\xb6\x8e\x2d\x0a\xfe\x8a\xc2\xa7\x4e\x01\xc7\x5b\x8c\x64\x3b\x13\x73\xf8\xb4\x12\xdb\x99\x63\xc7\x53\x1c\xe7\x54\x6e\x16\x48\x82\x36\x1d\x8a\x74\x40\x50\xb2\x92\xe8\x5f\xfa\x5b\xfa\xcb\x7a\x61\x03\x1c\x44\x91\xb2\xeb\x54\xdd\xdb\x6f\x75\xad\x3a\x31\x45\x80\x20\x08\x6c\xec\x79\xe8\x5a\x27\xc5\xc4\xdd\xe1\xdb\x9e\xdd\xbe\x9e\x77\xfd\x32\xb3\xaa\x90\x60\xa8\xac\xfe\xb3\xa0\x10\x2e\xcd\x70\x55\xd3\x5e\x0c\xff\xa5\xd5\x1c\xcb\x9a\x32\x07\x92\xbc\x5d\xf2\x57\xf2\x55\xb1\x68\x2c\x2c\xbf\xb8\x29\x74\x2c\x77\x4c\xeb\x1d\x57\xdc\x09\xd3\x48\x7f\xac\xd4\x7f\xf2\xea\x57\x35\xc6\x9c\xf8\x61\x31\x02\xa5\x5a\x59\x0e\xbc\x7b\xc3\xf6\x17\x20\xcc\x26\x79\xa1\xfb\x53\xb4\x55\xed\xe8\x99\x0a\x35\xd6\x3f\x93\xf2\x4a\x98\x9a\x20\xf0\x53\xb8\x05\x7a\xcc\xa5\x51\xa5\x90\x73\x85\x15\x27\xce\x41\x4e\x8a\x4b\x6b\x61\x81\xbf\xeb\xc8\x10\xfc\x4f\x8e\x05\x16\xf8\xdf\x1c\x2f\x54\xa8\xd1\xfa\x65\x81\xbf\xe5\x0c\x15\xd2\x9c\x50\xd5\xe9\xdc\xb7\xfd\x5d\xd5\xef\x20\x27\xea\xfa\x13\x55\xbd\xd5\xd5\x37\xf5\x80\xbe\xeb\xed\x53\xf5\xd8\x5d\x52\x6f\xaf\x56\x9f\x6d\x2c\xed\xe6\x62\x81\x2f\xda\x42\xa0\xcf\x43\x08\xcb\x57\xe0\x4f\xfd\xea\x8c\x84\x45\x8b\x9a\xa8\xbe\xa9\xe7\x1a\x96\x13\xd5\xc3\x50\xad\x39\xa2\x90\x29\x32\x72\x9c\xc2\xf3\x88\xfc\x14\x14\x3e\xe7\x14\xe2\xf0\xef\x94\x44\x54\x9c\xea\xd8\x80\xb0\xa0\x58\x1f\xda\x94\x45\x0c\xc2\x75\x8c\x71\x82\x49\x11\x29\x4c\xc3\xc2\x71\x27\x74\xb3\x04\x26\x61\xb7\xf2\x74\xbb\xae\x3c\xbd\x0c\xdb\x85\x42\x93\x39\x05\x2e\xc2\xf5\x25\x82\xaf\x43\xe3\x4b\x33\x0b\x8d\x67\xcc\x3c\xec\xac\x3d\x7c\xd3\xd6\xd4\x33\x06\xa4\x05\xec\xad\xfd\xd2\xbe\xd6\x23\x61\x3a\xdb\x52\x0e\xf8\xbe\x8e\xdf\x28\x24\x72\xa6\x24\x72\x66\xb3\x92\x07\x1b\xa8\x57\xfa\x76\xff\xfe\x7d\x7d\xc1\x0c\x53\xa6\x7f\x05\x8a\x2b\x8f\x42\xa2\x1e\xf5\x51\xbf\x53\x38\x2b\x16\x39\x27\x15\xe5\x5a\xb4\xfd\x10\x8b\xba\xac\x2f\x97\x94\x3a\xf5\xc2\x20\x36\x07\x6d\xcd\x7e\xbe\xbc\x22\x1d\x55\x39\x0a\x36\x21\x4c\x6b\xc5\xfe\x51\x23\x88\xce\xfd\x3e\x5a\x7e\x02\xa3\x10\xf2\xb1\xda\x85\x99\x7f\xde\x50\x05\xe9\xf5\x79\x1e\x92\x5c\x31\x42\xcf\x56\x57\x48\xf3\x66\x58\x67\xa5\x6c\x4d\x97\x66\x90\xb8\x69\x5d\x97\x75\x15\x41\x6a\xb3\xb2\x06\xc9\xf3\x90\xa4\x76\x80\x46\xaf\xee\xf7\x2e\xe0\x38\x6c\x2b\x3e\xdb\xe4\x8a\xcd\xf7\xd6\x2d\x8f\xe8\x60\x09\x0c\x39\x64\x1f\x39\xe4\x28\x24\xcf\x89\xa2\x68\x7f\x0e\x1b\x5b\xae\x2f\x96\x17\x40\x83\xc7\x8c\x1c\x87\x58\xc0\x4a\x2d\x82\xfe\x64\x66\x07\xf5\x0f\xfe\xfd\x3b\x2d\x96\x23\x52\xcb\x21\xaa\xe5\x88\x56\x26\x18\x2e\x97\x6c\xb9\x8a\x20\xb2\x19\x44\xb6\x07\x91\xed\x17\x2f\x8b\xd4\xb2\x84\x74\xb1\x7e\x36\x95\x43\xeb\x95\xba\xe7\x91\xef\x21\x2c\x83\x35\xba\x93\xb5\x2f\x9f\x9a\xdd\xdf\x58\xbe\x0b\x5c\x3e\x25\xd0\xb7\x94\xc8\xbd\x0d\x26\x13\x54\xd7\x04\x8b\x05\xf1\x0b\x32\x5e\xcc\x63\x1c\xa6\x0e\xae\x86\x2c\x0b\xbb\x30\x05\x03\x7e\xbd\x46\xf2\x55\x54\x7e\x9b\x59\x07\xfd\x89\x3b\x61\xab\xc6\xf9\x58\xf3\x66\xcf\x6a\x9f\x8b\x31\xf4\xb4\xd4\xaf\x2f\x6b\xdb\x9a\xf5\x79\x16\x14\xde\x84\xad\xca\x0c\x41\x8c\xc0\x23\x69\x23\x1f\xe2\x4e\x88\x77\x1d\x5d\x83\xae\x52\x6f\x1c\x74\xe2\x46\xcf\xc1\x0c\xa0\x96\x41\x92\xdf\x42\x37\x97\x70\x74\x0b\x33\xf9\x2d\x24\xbf\xbc\x27\x4a\xec\xb9\x76\x08\x73\x73\x38\x08\x49\x53\x6d\xd6\x0f\x01\x2b\x8c\x3c\xa9\x32\xcb\xea\xad\x19\x5f\x9b\x22\x59\x7d\x59\x2a\xc4\x14\x5f\xee\xcf\x1c\x01\xfe\x5b\x27\x01\x7f\xe4\xec\x49\xf0\x1f\x39\x12\xfc\xa7\xce\xbd\x51\x51\xc1\x7e\x41\xe1\x73\x27\xe2\xcd\xc8\x51\x08\xd6\xab\xbd\x13\x4b\x91\x23\x98\x86\x9a\x2f\x3e\x31\x64\xaf\x1f\x12\x54\x9f\x59\x5c\x88\x54\x58\x30\x53\x34\x51\x11\xc1\xfd\x70\x8d\xf5\x8b\x08\xe3\x15\x79\x1a\xba\x57\x09\xbc\x0f\xd7\xfa\x5d\x9f\x86\x30\x23\xfb\xe6\x9f\x1d\x0e\x09\x85\x3e\x32\x22\x47\x7c\xa5\xe1\x5a\x96\xe5\x70\x77\xd7\xc8\xab\xef\x43\xe4\x77\x7f\x08\x10\xb0\x87\x53\x21\x6d\x74\xc9\xac\x6c\x9e\xeb\x95\x3d\xe7\x64\x6d\x35\xfc\x32\xb8\xf6\x24\x9a\xf0\x34\x97\x3d\x7e\xe3\x73\x1e\xf0\xa0\x19\xc4\xbe\xcf\xe5\x2c\x15\xdf\x7b\x7a\xd1\x9e\xd5\xa2\xb0\x1a\xd2\x52\x10\xc2\x15\x9a\x60\x0e\x6d\x3f\xa4\x1b\x56\xcf\xda\xd0\x3f\xde\xc0\x49\xa8\xee\x3f\xa1\x0d\x83\xb7\x75\x9a\xf0\xc2\xc3\x45\xf0\xec\x3a\x4d\x32\xde\x0b\x45\x3a\xe9\xb1\xeb\x08\xad\x28\x36\x6b\x86\xfc\x7e\x60\x71\x98\x8a\x09\x0f\x7a\xb9\x88\x4d\x1f\x8c\xe1\xd2\x24\xf6\xac\xfd\x20\x56\x29\x42\x92\x4a\xbb\xa8\x2b\x7b\x65\xd6\xc6\xfb\x5c\x87\x1b\x14\xdf\xb2\xab\x00\xe5\xb3\xe2\x7e\xf7\x53\xf2\x3e\xd2\x5b\xf4\xf3\xee\x23\xaf\x1f\xf0\xd4\x0c\xf8\xd6\x80\x65\xcb\x66\x16\xfd\x93\x0d\xeb\xc1\x8a\xf6\x55\x7b\xcf\x92\x75\x8c\x0e\xa5\xf0\x65\x8d\xd4\x78\xa0\xed\x8a\x78\x38\x5e\xff\x2d\x06\x70\x4e\xde\x84\xba\x26\x36\x7e\xc2\xcf\x88\xf8\x98\xc1\x45\xff\x0c\x42\xa2\x05\x00\x0a\x37\x92\xd2\x7a\x05\x4c\x0a\x87\xab\x13\xab\x9b\xbf\x45\x69\xfe\xbe\x37\xaa\x3c\xbc\x50\xf3\xae\xf9\xa8\xa2\xcc\x9f\x31\x69\xa3\xfa\xf3\x47\xd8\x5d\x86\xfb\x30\x6c\x77\xe5\x43\xa1\x59\x4f\xe9\x43\xe8\xce\x12\x78\x11\xba\x3f\x12\x62\x5d\x73\x91\x45\x99\x7c\xa5\x60\x63\xef\xe6\x9a\x25\xc1\xf3\x38\xb6\xe0\x43\x48\xe1\xe5\x9a\x53\xba\x53\x8a\xe1\x1f\x3b\x7b\x1d\x11\x01\xbf\x7c\xe9\x34\x98\xa8\x46\x76\x93\x5d\xf2\x97\x06\x24\xf4\x3d\xfd\xba\x92\x24\xba\xa8\xff\xd7\xe7\x90\x73\x2c\xa4\x38\x23\x6f\x24\x28\x31\x26\xa1\x54\x1d\x85\x6f\x5a\x7b\xf9\x2a\xbc\x45\x49\x9d\x14\xb6\xce\x4f\xeb\xa7\xec\x5d\x39\x65\xfe\xf7\x57\x21\x64\x21\x24\xf6\x6b\xa3\x22\x3d\x5f\x7d\xb4\xdc\xb5\x1b\xa4\xe3\xec\x02\x09\xf9\x31\x12\xf2\x23\x24\xe4\xaf\x21\x75\x85\xfd\x0d\xeb\x73\xdc\xa9\x06\xe0\xfa\xfa\x7f\xc2\x3e\xb9\xb5\x02\x60\xbe\xbe\x02\x20\x2b\x9a\x4d\x9d\x42\xb8\xce\x15\xe5\x5f\xa9\x09\x28\x97\x6a\x02\xa6\xf8\xc3\xcf\x33\x99\x4e\x10\x60\x30\x81\x02\x1f\xdf\x48\xa2\x4b\xba\x62\xaa\xfb\xaf\x8d\xb2\x81\x9c\x8e\x4f\x48\x02\x4b\xa5\x03\x39\xd5\xee\xe9\xef\x50\x30\xd9\x5e\x40\xe2\xb9\xbb\x82\x58\x61\xea\xe7\x99\x45\x41\x78\x2b\xcb\xdc\x6d\xb6\xff\x46\xf4\xb6\x45\x4e\x62\xb3\xb1\x65\x39\xc2\xf6\x22\xc0\x5d\xfc\x11\x1a\x56\x5c\xd8\xde\x15\x1d\xab\x7f\x9d\x13\x85\x9c\xaf\x8a\x74\x2b\x0b\xaa\xd6\x03\xc9\xce\x54\x92\x77\x21\x85\xc4\x6b\x0f\x4b\xad\xd4\x07\x95\x7b\x40\xeb\x0c\x4e\xd5\xba\xd5\x26\x11\x87\x30\x89\x88\xa2\x7e\x6a\x12\xff\xfa\x0b\xb7\x5a\x3f\x54\x8d\x33\x82\x83\xb4\xe9\xad\x65\x3a\xb1\x77\xcb\x9d\x1a\x52\xf7\x37\x22\x4c\x0b\x2a\x5c\x3d\xb5\x0d\x4f\x16\xc0\xbd\x56\xf6\x0b\x47\xfc\xe6\x60\x21\x3e\x5f\x52\xdb\x1b\x5f\x10\x01\xcd\x93\x4b\x8d\x25\xc8\x54\x96\xb3\xb0\x5a\x87\x82\x0d\x8b\x56\xae\x0c\x07\x44\xc2\x9b\x54\xeb\x73\xbe\xa5\x20\x6d\x7f\x0f\x66\xe4\x5c\xa3\x13\x5a\xae\x8b\xf4\xf4\xba\x20\xe4\x0d\xbc\xf9\x20\x8c\x78\x1c\x18\x9f\x92\x05\x85\xdc\x5b\x87\x56\x93\x3f\xdd\x61\xc5\x74\x2e\xe3\xd9\x9e\x50\x18\x66\x30\xd2\xa1\xcb\xea\xeb\x99\xb7\xde\x47\xa9\x3e\x9a\x6c\x8e\x26\x8d\x91\x5c\xd8\xac\x3e\x2e\xe6\xbd\xf4\x15\x0f\x29\x71\x85\x7d\xaf\x0b\xe5\x9c\x4a\x32\x27\xcc\x43\x41\x62\x5f\x2b\xec\xbc\x76\x7b\xfd\xf0\x4f\x51\x78\x14\x1e\xa0\x89\xa8\x35\xa0\x51\xcd\x8f\xdb\x5e\x7d\x86\xe5\x2d\xdb\x2b\x31\x30\xaf\x89\xce\x26\xb4\xaf\x70\x0f\x54\x4d\x05\xd7\x54\x74\x31\x30\xa6\xad\x64\xbc\x82\xfc\x5d\xf2\x57\x6e\xa3\x41\xcc\x66\x5f\x4b\x78\xc5\x24\x24\x5e\xf1\xc6\xc2\xd5\xc2\x03\xdf\x65\x4b\x8f\x32\x5b\x1b\xc6\x7c\xfd\xf8\xa2\x19\xf5\x58\x1f\xe7\xfe\xfd\xf2\xb2\x18\x34\xc5\x41\x23\x37\x35\x15\x3b\x3d\x94\xb2\xf5\x6b\x18\xb0\xfa\xcb\x70\x33\x52\xf4\x92\xf6\x25\x4a\x80\x78\x91\x17\x17\x3e\x8c\xf8\xd6\x9f\xc9\x78\x46\x7c\x0f\xc4\x60\x1b\x98\x12\x29\x52\x0f\x92\x8d\x91\xf9\x8d\xf5\xd4\x8b\xa5\x2a\x64\xa4\x32\x0e\x72\x97\xfc\xc5\xcd\x57\x94\xda\x3d\x0a\x91\xd7\xcd\x96\xa4\x9e\x76\xb6\x40\x0d\x68\xdb\x96\x97\xde\x17\xab\xc4\x50\x17\xc3\x95\xb6\xa7\x1d\xa8\x3c\xe0\x1b\x8a\x69\xce\x3d\xe0\x03\x84\x41\x7d\x4a\xbc\xce\xd7\xeb\x7a\x25\x09\xba\x10\xa9\x9e\x99\xe7\xbe\x82\xd8\xeb\x24\x6e\x46\x46\x2d\x66\xf2\x49\xe8\xca\xbc\xad\xc9\x0d\x4c\xa7\x7b\x17\x44\x97\xa6\xbe\x7f\xff\x82\x70\xc3\x7e\xa0\xd2\x6c\xcd\xa2\x7c\x93\x80\xe6\x60\xb3\x2e\x53\xaf\x4d\x96\xd6\xdc\x0c\x2d\x35\x8a\x7a\x92\x7d\x4e\x04\x45\x1a\xfb\x8d\x83\xe7\x91\x7d\x14\x44\x02\x0f\x66\xe4\xb3\x84\x11\x48\x0a\x6f\x4d\xfd\xe5\xdc\xd5\xc5\xf9\x85\xab\xab\x8b\xe5\x20\xe9\x83\xcd\xdf\x43\x8a\xc7\x77\x46\x4e\x52\x98\x91\xd0\x03\xa1\xb5\xb7\xed\xe3\xe5\x38\x9e\x56\xc9\x27\xee\x27\xa1\xde\x9e\xbb\xc9\x83\x5c\x91\x9c\x07\x12\x4c\x21\x99\xa2\x40\x70\xec\x11\x6e\x18\x46\x29\xe1\x9d\x24\xf6\x43\xad\x23\x06\x2c\x68\x37\x97\xc8\xa2\x56\xfe\x13\xe3\xd1\x83\xad\x3f\x48\xbe\x21\x37\x48\x32\x10\xf4\x41\x42\x9d\xe1\x82\x42\x7f\x1d\xb2\x2a\x90\x43\x21\x85\xdf\xe3\x36\xb3\xbd\xdf\xbf\x9b\x08\xa1\x38\xc6\x0c\x96\x0d\xd8\xe8\x54\xa4\xae\x8b\x70\x8c\x5c\xb1\xa0\x89\xeb\x83\x70\x39\x48\xf7\x84\x48\x85\xf5\x99\x22\xf1\x3c\xce\xb8\xc6\x4a\x9f\x50\x64\x2c\x07\x37\xa6\x4f\x90\x8a\x59\x5d\x50\x98\x78\x6d\x8a\xc5\x33\x92\x50\xfb\x2a\x8d\x12\x24\x0f\x70\xd9\x05\x13\x56\xa1\xf5\x56\x7f\x85\xa2\xee\x7a\xf7\xc7\x89\x33\xf1\xc8\x9c\xf4\x3d\xbd\x0b\x7a\x6f\x0d\x06\xbd\xe8\xc0\xa0\xcb\x83\xd1\x52\x45\xdd\x02\x53\xc5\xe7\x6c\xd8\x9b\x0f\xff\xe8\x73\x32\x23\x97\x9e\xa6\x51\x7f\x90\xd1\x00\x55\x0c\xd7\x77\x9c\xf3\xb0\x98\xf2\xc8\x99\x93\x0b\x8d\xe9\x67\x64\xea\x95\x21\xcb\x33\xcf\x7d\x0b\x73\xaf\xd5\x76\x54\x24\xbb\x2a\xd9\x9e\xc7\x55\x96\x2a\x5e\xa7\xa4\xbc\x46\x49\x35\x07\x70\xe1\x48\xc5\x01\xdc\x95\xaa\x36\x52\x82\xcc\x09\xd7\x53\x3d\x22\x1c\x7e\xb1\x2f\x6a\x30\xb5\xfc\xdc\x66\x5f\xc0\x97\xce\x09\xe1\xb6\x8f\xe0\x80\xbe\x61\x4a\xfa\xf1\xbe\x3b\xfb\x8b\x65\x36\x09\xdb\x9e\xad\x1b\x32\x2f\x47\x2c\x38\xa5\x9c\xaa\x8f\x91\x8d\xf1\x6a\x25\xcb\xf0\x71\x2f\xd6\x9f\x57\xb1\x40\xdb\x8d\x1e\x6c\x53\xf5\xd0\xc1\xb7\xf5\x7e\x0f\x9b\x23\xed\x34\x47\xda\x6a\x8e\xf4\xae\xd9\xa3\xf4\x3e\x67\x6e\xf1\x31\xea\x53\xb1\x0f\x39\x22\x0c\x7e\x79\xdf\x1d\x86\x59\x42\xbe\xd0\xf1\xbe\x33\x23\x53\x8e\x49\xc3\xf4\x0d\x66\x7b\xdf\x1d\x44\xdc\xa3\xa1\x2e\x6f\x33\xf3\xe0\xda\xd3\xdd\xa1\xc2\xf3\xad\xa2\xc2\x0f\x54\x48\xaa\x15\x5a\x40\x94\x53\xf0\xd4\x6b\xfc\x57\xda\xe6\x54\xff\xda\x95\xb4\x66\x1c\x19\xbe\x42\xb3\x74\xe3\x19\x87\x88\xbd\x2e\x40\xc6\x80\x3f\xf0\x8f\x4c\x7c\xad\xb7\x2e\x52\xcd\xff\xe9\x08\xf0\x5f\xab\xfe\x1f\x1c\x09\x7e\xdf\xe1\xea\xa1\xe7\x9e\xfb\x41\xc0\xb1\xe7\x3e\xb0\xff\xeb\x01\x5c\x79\xee\x0b\x41\x46\x0f\x86\x14\x76\xee\x08\xef\xb5\xf4\x6e\x5b\xe8\xc1\xc7\xec\xfe\x98\x3b\x7a\xe7\x7e\x3a\x88\x60\x5f\xe7\x20\x31\x9f\x41\x7d\x8b\x9a\x00\xa3\xc3\xad\x71\xdd\x7d\x09\xea\xd3\x2c\x14\x75\xfd\x23\xc7\xb2\x16\x50\xec\x06\xb7\xbd\x9f\x6a\x1d\xcb\x08\x6c\x85\x75\x8b\x03\x74\x63\x0e\x50\x21\x24\x95\x07\xe8\xce\xa0\x55\x1d\x0b\xf6\x6c\x65\x7e\xf9\xed\xd3\x2b\x80\xa5\xbb\x1e\xb4\x37\x59\x28\x50\xca\x29\x35\xdf\x42\x69\x2b\xe4\x16\x53\xc4\x50\xef\x35\xc7\xc8\x7b\xbd\x7a\x3c\xda\xe6\x6f\x22\xd7\xcd\x70\xed\x38\xc9\xbb\x71\x10\x29\xe6\x46\x54\xc8\xa9\xc2\x4f\x9d\x90\xba\xa0\xf0\xc6\x5b\x2b\xab\x17\x05\x19\x0b\x17\xa6\x03\xaf\x43\x8f\x5b\xe6\x51\x7a\x8a\x22\x39\x7b\x83\x32\x39\xfb\x06\x91\xe2\x6b\xe6\x10\xaa\x5f\xaf\xc1\x73\xf3\x0d\xeb\x7f\x3d\x28\x74\x66\x99\x7b\x1e\x12\xaf\xac\xb0\xb6\xaa\x4f\xc4\x8f\x57\xc8\xf6\xb5\x11\xb7\xca\x45\x1a\xe2\x46\xc7\x68\x0e\x0a\x5a\x0a\x37\xc6\x8d\x24\x4f\x89\x1b\xa3\xfb\x38\x22\x0f\xff\x95\xf3\xd3\x54\x99\xc4\x04\x83\xc8\x90\x74\x6e\xf8\xe5\x02\x42\x49\x4d\x31\x4a\xf4\xcd\xec\x2a\xd1\x52\x61\xe2\xa3\x14\x2e\xb5\xee\x54\xc3\x5a\xae\xe3\x8c\xad\x05\x32\x6a\xa1\x82\xb2\xd7\xe1\x2d\x2f\xd5\xad\x12\xe2\x90\x74\x22\x2a\xc5\x63\x20\xaa\x42\x36\xa9\x16\x95\x74\x40\x72\xa4\xdb\xa2\x49\x78\x0e\x48\x94\x02\x5b\x4d\xdc\x98\xe3\xdd\x15\x48\x39\xe7\x24\x56\x5f\x81\xb9\xad\xe8\xb3\x95\x6d\x09\xd4\x0c\xde\x38\x31\xb0\xa7\x4e\x60\x7b\xcb\x18\x42\x2d\xcc\xd4\x9d\x91\x8f\x21\x48\x60\x14\xfa\xee\x8c\x7c\x52\xd7\xe9\xca\x48\xcb\x39\x21\xa4\xcd\x2e\xc6\xa1\x93\x63\x6a\x08\xfc\x91\xa7\x8e\x0f\xec\x9b\xd3\x57\x2f\x9a\x2a\xc8\x45\xda\x8c\x6d\x33\xb2\x63\x36\xf0\x13\x87\x77\xc8\x06\xfe\x0c\x51\x36\xa4\x4e\xd5\xf6\xaa\x68\x3b\x33\x6d\x50\xb5\xc9\x1c\xdb\xde\x86\x84\xd7\xa9\x75\xed\x30\x0b\x7d\xe4\x84\x3a\x72\x19\x39\x22\x12\x7e\x61\xd9\x52\xf4\xba\xa5\x74\x25\x3f\x55\xeb\x13\xc7\x2d\x4f\x8c\x86\x0d\x58\xf7\x4e\x9a\xb0\xbe\x8d\x0b\x39\x71\x67\x44\xa0\xbb\x12\xa4\x6a\x29\x27\x08\xf9\x13\xdb\x83\x4b\x77\x62\xfb\x70\xe1\x56\xdf\x93\xe8\xef\xb9\xa4\x30\x71\x33\x32\x23\x6f\x3c\xe8\xdb\xde\x15\x7e\xf5\x85\x1b\x8c\x6b\x8c\x0d\xce\x6f\x42\xe1\xe2\x2b\xa5\xce\x45\x73\x5b\xd4\x82\x63\x82\x0c\x0a\x17\x25\x12\xbe\x70\x6f\xc8\xdc\x03\x0f\xdd\x12\x99\xda\xd8\x4b\xf7\xa2\x5e\x09\x5a\x3f\xfb\xd4\x99\xba\x17\xf8\x25\xd5\xc4\x44\x31\xb1\x12\xd7\x4d\xdd\x1b\xb2\x53\x0d\x16\xa9\xc1\xa6\x2b\x83\x79\x73\x67\xda\x18\x4a\x36\x86\x7a\xd2\xc4\x19\x7b\xcd\x75\x7c\x8a\xeb\x78\x5d\x57\x80\x56\xe0\x87\xae\x5f\xd7\x20\x6c\xb6\x4b\xc7\x33\xf2\xb2\xfc\xe1\xcc\xc8\x97\xf2\x07\xf8\xa9\x46\xc0\x2f\x42\x72\x6f\x54\x43\xad\x97\x88\x89\xae\xdd\x2d\xd7\x75\xc9\xb5\x7b\x40\x42\x35\x33\x45\x4d\xef\xdf\xbf\xb6\xbd\x31\xe2\x9b\xcf\x4a\x0a\xf9\x24\xc8\x35\x52\x53\x4a\x9d\x2c\x5d\x9d\xc8\xb5\x7a\xc7\x65\x09\xe1\x2f\x42\x72\xa9\x3e\x9b\xa7\xc0\x73\xd8\xe1\xe4\xd2\x68\x69\x16\x14\xbe\xad\x65\x19\x4c\xb1\xa0\x7a\x10\x88\x7a\xe8\xc8\x33\x6e\x0b\x1f\xc4\x5a\x17\xe5\x54\xbb\xa9\x2f\x28\x7c\xf6\xdc\x19\xf9\xa0\x35\x52\x46\x6b\xfa\x66\xd7\xfa\x4a\x75\xa2\x04\xcf\xbd\x49\x60\xdf\x73\x67\x09\x9c\x76\x52\x93\x57\x92\x24\x0f\x50\xe6\x7c\xef\xdd\x3d\x64\x4d\x6c\x24\xcd\x20\x09\x6d\xf3\xe6\xb6\xb7\x8f\x61\xeb\x55\x4f\xae\x63\x84\x40\xb8\xa2\x88\x46\xdb\xed\x12\xb8\x97\x50\xf5\x7b\x7d\xa6\xb0\xfe\xff\x39\x4a\x39\x8f\xf8\xb6\x49\x66\x71\xd6\xf9\x41\xef\xd4\x7e\xee\x1a\x21\xc3\x66\x9f\x16\x14\x7e\x7a\xdd\x0a\xfd\x7e\x04\x9b\xdb\xfa\x1d\xe5\x63\xf0\x68\xa8\x4d\x37\xeb\x9f\x1b\xf1\x2d\x3d\x2f\xd5\xf7\xcb\xfa\xbe\x8f\x86\xd5\xf0\x68\x8f\xe9\x54\xf4\x36\xe6\x9f\xfe\xff\xa5\xfa\x37\x85\x43\xaf\xdb\xfe\x3a\xfc\x33\x19\xcf\xc9\xa1\x07\xc9\xff\xfe\xdf\x23\x38\x21\x42\x6d\xc3\xe8\x7e\x32\x56\xa2\xb7\xa0\x8e\xa4\x8e\xe2\xee\x7f\xac\x51\xa1\x1c\x6a\x19\x0b\xb5\xae\xf0\x61\xcd\xbb\x4e\xc8\x8c\xfc\xf0\x20\x19\xf4\x39\x91\x14\xf6\x70\x0b\x35\x58\xbd\x58\x33\xfe\x07\x35\xbe\x35\xc4\x2a\x06\x7a\x13\x5f\xde\x61\xcf\x4b\xd8\x1d\xf1\x2d\x9d\x2b\xe2\x8e\x90\xeb\x21\x32\x13\x77\x0c\xcd\x7e\xa5\x30\xc1\x0b\x01\x43\xd8\xa7\xf0\xc9\x73\x13\x06\xe7\xea\xd6\x7e\x08\xfb\x1e\x7c\xf2\x28\xbc\x5b\xf3\x69\x07\x12\x88\x74\x13\xe8\xb4\x23\x5d\xe7\xd9\x25\xd1\xa6\x3f\xb1\xa0\x14\xfe\xfa\x5a\x44\xab\xaa\x5d\x49\xb2\x3b\xe6\xfc\x10\x59\xf7\xae\x68\xab\xfe\xc7\x83\x63\x63\xd6\xd7\x4e\xbc\x20\x57\xc7\x4e\x9a\xf6\xd8\xb2\x18\x84\x2e\x00\xf1\x0a\xdd\x26\x0f\x88\x65\x2c\x0a\x99\x05\x33\xf2\xce\x83\x4f\x39\x10\xe1\x0a\x6a\x7b\x57\xda\xbc\x53\xc5\xc5\x9c\x7b\x44\x60\x29\x43\x75\xbb\x88\xa7\xc1\x9b\xec\x4c\xdf\xd4\x45\x1b\x74\x52\x19\xbc\x7f\x6a\xee\xa7\x93\x09\x4f\x64\x71\xf7\xd8\xd8\xa7\x02\x4b\x17\x4e\x3e\xf1\x74\x31\xe5\x7d\x34\xc5\xf8\xa6\x50\x8a\x70\x67\x24\xc9\xc0\x62\xd7\xd7\x71\xa4\x33\x27\x3d\xb8\xca\x52\x2c\xc2\x77\xdc\x50\x88\xed\x86\x64\x4e\x44\x86\x2b\xf2\x59\x2b\x2d\x79\xe7\x7a\xb3\x63\x45\x5a\x8f\x81\x9d\x3a\x58\x77\x7b\xea\x08\xc8\x9c\xc4\xce\x80\x9d\x39\x58\x7b\xdb\xf3\x1d\xac\x98\xe1\x1d\x38\x58\x92\x1b\x05\xbd\x05\x85\xbc\x6b\xcc\x5e\x1e\x11\x84\xe0\x8d\x44\xc7\x74\x51\x60\x99\xdb\xca\x1b\x4b\x11\x4d\x08\x5d\x80\x9f\x99\x30\x95\x99\x05\x8f\x86\xdb\x4f\xf8\x43\x5c\x94\xc0\x02\x0c\xe3\xc7\x1f\x97\x16\x6c\x3d\x32\xd7\x13\x4b\x63\x76\xb5\x25\x16\x1e\x94\xaf\x14\xd2\x6c\xed\xe1\x7a\xbc\x12\xbd\x85\x37\x6b\x81\x58\xbf\x7f\x3f\x5e\xa8\x69\x3f\x1e\xdc\xc5\x5f\xf3\x7f\xa2\x1a\x99\x59\xbe\x28\xeb\xa0\x7e\x9c\x91\x84\x8e\x47\xce\xb0\x4c\x88\x7b\x9b\x57\xe9\xd6\xa8\x31\xcd\x87\x4f\x37\x64\x63\xa6\x4f\x87\xc5\xad\x72\xb2\xa3\xcd\xf2\x5e\x39\xe1\xd1\xc3\x51\x71\xaf\xa4\x0d\xa3\x27\xe5\xbd\x92\x3e\x6c\x8e\x36\x8b\x7b\x25\x8d\xd8\xdc\xde\x2a\xee\x95\x74\x62\xf3\x71\x79\xaf\x96\x1e\x60\xb8\xbd\x21\x9b\x2b\xb3\xb5\xb5\xbd\x81\xf6\xfd\x30\xbb\x9d\x4b\xf1\xba\xe1\x54\xad\xde\xc6\x8c\x44\x78\x56\xe8\x86\xc2\x9f\x59\xd6\x45\x66\x57\x96\x76\xab\x09\x01\x7a\x37\x36\x9f\x3a\x9b\x4f\x9a\xb0\xd0\xa4\xb9\x5b\xc3\x26\xd1\x1d\x35\x13\x3a\x0c\x8b\xa5\x6d\xe6\x67\x68\xe6\x62\x18\x36\xf3\x2e\x8c\x56\x17\x71\x65\x05\x91\xbe\xc6\xd9\xad\x2a\xf2\x19\xc9\xf4\xea\x40\xee\x32\x66\x1c\x08\x47\x9b\x7f\xba\xf9\xef\xdf\xcf\x31\xde\xa9\xb2\xf9\xfd\x62\x9f\x1c\x4c\xa6\x27\xc0\x1b\x39\xc9\xc2\x30\x71\x3e\x23\xf9\xc6\x88\x82\x74\xe5\x00\xd9\xd6\x20\xeb\x36\xb6\xcc\x48\x68\xde\x87\xe7\x53\x18\x4b\xc8\x34\xd3\x3e\x31\x11\x6b\x17\xb2\x59\xba\xa0\xd0\x37\x9d\xa6\x59\x4b\x27\xc2\x70\xb7\x37\xe9\x83\xad\xdf\x4a\x06\x9a\x74\x9c\x29\xe0\xae\x78\xd6\x75\xe6\xa5\x9b\x32\xb4\x5e\x30\x22\xe9\xc6\x68\xc5\x4b\xde\xcb\x40\x77\x20\xd2\xed\x67\xea\xc2\x67\x64\xeb\x0f\x39\xd8\xa4\x2d\x69\x92\xcb\xde\x53\xd5\xb5\x14\xa3\x96\x01\x83\x0f\x66\x24\xcd\x10\xc3\x37\x20\xc4\xb4\x8c\xca\x96\x47\x8d\x96\xcd\xb2\xe5\x71\xa3\x65\xab\x6c\x79\xd2\x68\xd9\x2e\x5b\x9e\x36\x5a\x1e\x96\x2d\x15\x60\x99\xa6\x47\xaa\xa9\x01\x61\xda\x2f\x7b\x0d\xf9\x7e\x8e\x4e\x45\x7f\x0e\xc7\x89\x33\xfc\xf3\x39\x32\x6d\x63\x81\x3c\xdb\xc5\x9a\xa7\x9a\x67\x76\x4e\x2e\xd5\x12\x54\x60\xaa\x0d\x0e\x59\x37\xeb\x72\x91\x01\xd6\x11\x34\x40\xf6\xba\xbc\x3a\xab\xd9\x19\xb2\x75\xe1\x29\x8a\x0c\xfd\x91\x6c\x3c\xe2\xdb\x7f\x08\x4c\x5f\x24\x37\xf8\x82\xc2\xbc\xf3\xa5\x37\x64\xa6\x5e\xfa\xb3\x7c\xd5\x97\xf2\xea\x65\x79\xf5\xb6\x7a\xfd\x4d\x17\xbe\x47\xb2\x6a\xe8\x15\x09\x19\x99\x91\x6b\xfd\xd9\x6a\x49\xe6\xfa\x72\x20\xe9\x83\x47\x7c\x1b\x81\x7c\x2f\xeb\xb4\x96\x86\x0a\xf2\x36\x24\xe4\xee\x8c\xdc\xa8\x27\xf3\x88\x70\xe4\x34\xd4\xc5\x40\x7d\x5c\x4e\xd1\x38\x7f\x93\x95\xce\xaa\x17\x24\x87\xca\x82\x25\x9e\xf1\xaa\xb3\xac\xc5\x33\x4a\x30\x4f\x71\x4a\xc7\x1c\xc3\x00\xbe\xaf\xd9\xd3\x39\xd9\xcb\xd0\xd2\x33\xc9\xd0\xa3\xf1\x3a\xc3\x66\x0a\x43\x74\x2e\x6f\x7b\xb2\x59\x6f\xa7\x3c\x14\x05\x01\xd9\x76\x9a\x83\x9b\x51\xa1\xda\x0c\xfc\x89\x9b\x61\xae\x5e\x9a\xab\x61\xa9\xd1\xd9\xfa\xd7\x87\x19\xd6\x1e\xdf\xbc\xeb\xe3\xc3\xa5\xc7\x46\xd5\x63\xdf\x33\x18\x8d\x74\x68\xfe\x32\xfa\xc0\xa6\xcd\x5a\xcb\x70\xa9\x65\x58\x6b\x69\x0c\x57\x6b\xd9\x5a\x6a\xd9\xaa\xb5\x6c\x2f\xb5\x6c\xd7\x5a\x1e\x2e\xb5\x3c\xac\xb5\x3c\x5a\x6a\x79\x54\x6b\x79\xbc\xd4\xf2\xb8\xd6\xf2\x64\xa9\xe5\x49\xad\xe5\xe9\x52\xcb\x53\xdd\xd2\x40\x32\xfa\x83\x4c\xfc\xde\x82\xc2\x71\xd7\xc1\x41\x96\xda\x63\x15\xb7\xf7\x8b\x45\x8e\x00\x76\xe5\x14\x2d\x82\x2a\xca\x95\x54\x59\x60\x13\x60\x3f\x75\x10\xf5\x55\xa6\xa4\xa3\x9d\x35\x10\x7c\x44\xfa\x29\x98\x4c\xb3\xa2\x48\x34\x9b\x50\x98\x3a\x33\x72\x9c\x01\x86\xb0\x02\x3a\xfc\xe4\x19\x3c\xde\xe4\x0f\x75\xc4\x1c\xa6\x97\x45\xae\xdf\xb2\x40\x32\x82\xa9\x8f\x68\x91\x6d\xf6\x2a\x6b\xf6\xd7\x59\x67\xaf\x32\xf4\x36\xd3\xe6\x83\x05\x85\x37\x9d\x78\x07\xd1\xc5\xe0\x3c\x27\xa8\xfb\x39\xc8\x6e\x09\x4c\x31\x8e\x94\xb5\x5c\x27\x37\x89\xcb\x3a\xf3\x9b\xd6\x65\x88\x5c\x7d\x33\x57\x13\x97\x4a\x60\x60\xe0\x5d\x29\x21\x0e\x43\xd1\x0f\x1d\x1f\xbc\x4f\x4e\x8a\x4b\xb9\x4e\xcb\xe5\x85\x0e\x07\xef\xc2\xc1\xf2\xea\x09\x78\x9f\xb5\x0c\xf8\x51\xb8\x98\x3f\x20\xca\xf6\x7e\xe4\x2c\xc6\xd4\x01\x2c\xc5\xf5\xbc\x37\x34\x49\x00\xa2\xec\x88\x5f\xf0\x1b\x0b\x98\xc9\x01\x30\x65\x71\xce\xab\x54\x05\xf5\x74\x9d\x57\xda\xfe\xb7\x2f\xdc\x7a\x96\xcf\xdb\x72\x98\x16\xb5\xb9\xfe\xa5\xfc\xa5\x45\xa1\xaf\xbf\x9f\xbc\xb4\x23\xbd\xe8\x47\xe3\xcd\xfb\x2d\x73\xbb\x53\x38\x60\xce\x87\x7d\x93\xf3\x01\x05\x4c\xb3\x1a\xa5\x08\x5a\xde\xa8\x64\xd5\xe2\x56\x23\x47\xc4\x4a\x46\x88\x4a\x54\xde\x4f\xc9\x47\x81\x33\xbd\xa9\x72\x36\xc0\x51\xeb\x71\xe9\x10\xc4\x2d\x10\x5f\xeb\x95\xff\x76\x52\x90\x50\x39\x47\x7f\xcb\xb4\xc1\xe6\x73\xe6\x92\x77\xbe\x9b\x47\xcd\x5c\xc3\x09\xd9\x4b\xc8\x3b\x9f\xec\x32\xc9\xed\x24\x9d\x11\x6d\xcb\xa3\x70\x92\xd5\x7d\x77\x4d\xde\xee\x1d\xf5\xb5\xa9\x50\x12\x38\x85\xfd\xec\xb6\xf4\x85\x45\x1c\x88\x49\x8b\x32\x36\x19\x6a\xc6\x26\xc3\xce\xd8\x44\xea\x8c\xaf\x25\xc9\x88\x09\xac\xb0\x19\x70\xf4\xf6\x62\x58\x27\x04\x03\x1a\x98\x09\x6c\xc8\xcd\x5f\x6e\xfe\x4a\xf3\xd7\x9c\xb9\x2b\x25\x0a\xdf\x90\x2b\x85\x13\x2c\x0b\xee\x8d\x0c\xa0\x2b\x11\xf7\x34\xc3\x7c\xd6\x96\xa5\x8e\x9b\xfa\xf7\xcc\xd1\xf5\xa2\x4d\x56\xea\x2b\xe7\x4a\x1d\x3a\xbc\xb7\x80\xf7\x6d\x9a\x90\x03\x92\x29\x16\x0a\x32\x86\x3c\x27\x66\x2e\xc1\x38\x23\x9d\xd1\xbe\x32\x5b\x3d\x43\x3b\x58\xa5\x5f\x57\x4c\xda\x39\x1a\xc2\x6c\x46\x8d\x1a\x53\x61\x0d\x6b\x87\x25\xff\x90\x3d\x8f\xf7\xa2\xa4\x27\x2f\x79\xef\x9a\x65\xd2\xd2\x58\x04\x43\x18\xda\x71\x32\x73\x85\xed\xf9\x80\x2e\x53\xc7\xda\x1f\xf8\x14\xfd\x81\xbd\x03\x74\x0c\x64\x67\xc5\x8b\x3f\xe7\x24\x24\xfb\x19\xac\x0d\x3b\x39\x22\xa7\x19\x62\x60\xa1\x96\x06\x93\x2d\xe7\xcb\x98\x88\x23\xb2\xec\xe3\xc7\x07\x8c\x48\xdb\xfb\x8c\x17\x1c\x2f\x32\x46\x72\xbc\x98\x91\xf7\x19\xa8\x4b\x10\xea\xb7\x0e\x1e\xe8\xc4\x9c\xcf\xf1\x17\x32\xb1\x8a\xcb\xf9\xd9\xcd\x6f\xc9\x4e\xa1\x62\x4e\x7e\x2a\xaa\x3c\xda\xfc\x43\x00\x6f\x18\xbf\x23\x46\x38\x05\xe6\x8e\x36\xff\x50\xf3\x1b\x0d\x46\x74\x43\x49\x32\xb9\xcd\x52\xaa\x7e\x08\xf0\x95\x80\xa5\xd5\xcb\x9b\xc0\xa8\x92\xb4\x98\x8b\x62\x14\x83\xd1\xa6\x92\x52\x2a\xd6\x99\x19\xd6\x99\x81\xaf\xae\xce\xd4\x97\xb2\x4f\x9a\x7b\xc6\xa8\xac\x06\x93\xc1\x37\x1e\xff\x21\x9a\xf8\x8a\x6f\xe8\x84\xc5\xed\x3c\xf2\x4a\xf6\xb0\x15\x16\x4d\xab\x87\x38\xdd\x28\xe5\x89\x6d\x27\x71\x47\x0f\x41\xb8\x98\x68\xd4\x64\xfb\x68\x49\x09\xb1\x55\xf4\x43\xd6\xbb\xbb\xdf\x66\xd1\x0f\x39\xf5\x35\x1d\x47\x4b\xfc\x99\x04\xdc\x8a\xad\x82\x51\x53\xdf\xa3\x00\x62\x6e\x2e\x57\x38\xb0\xea\x99\xd1\xfa\x67\x86\x4e\xe2\x6e\xaa\xef\xdb\x5c\x37\x1b\xd3\x69\xdd\x12\xe0\x0a\x8c\x40\xb8\x8f\xdb\x3b\x55\x69\x32\xd6\xf4\xc2\xfc\xd1\x6b\x84\x95\xb7\x99\x02\xa5\x44\xd7\x0a\x5f\x50\x78\x7d\x4b\xdf\xad\x5a\xdf\xc3\xee\x13\x80\x45\xf4\x4d\x9a\xa9\x52\x54\xe0\x20\xe9\x58\x3a\x38\x50\x82\xcb\x88\xd1\x6d\x3f\x5a\x50\xd7\xc0\x45\x7e\x19\xdf\xf4\xac\x73\xb2\x1f\x3a\x9e\xfc\xd2\xfa\x64\x7d\xea\x2f\x1a\x4f\xe6\x85\x3b\x40\x8b\x8e\xa4\xc8\x41\xca\x97\xcc\xf8\x3f\x3b\x42\x16\x74\x9a\xf9\x45\x2d\x9c\x34\x19\x1f\xa8\x33\xfc\x13\xb8\xfa\x73\x45\xa9\x73\x40\xf0\xf2\x27\x05\xbc\xb1\xd0\xb2\x57\x10\x82\x46\xf0\x78\xe0\x9f\x75\xbb\xf6\x1f\x91\x1c\x7e\xb1\xd4\xb9\x91\x64\xc2\x74\x60\x5a\x83\xf9\xaf\xf5\xc0\x9d\xd8\x54\x1f\xae\x57\x61\x04\x83\x91\xfa\x55\xdd\x97\x9a\x80\x36\x20\x5e\x0f\xf1\xa3\x32\x7d\x37\x64\x85\xa2\x7d\x4f\x2e\x68\x3d\x20\x8c\xb7\xf9\xa6\xd6\x42\x3c\x2f\x31\xad\x73\xe9\x41\xfb\xac\x42\x14\x44\x28\x99\x17\xdb\xd5\x82\x9c\xe7\x44\xdd\xc4\x0b\x9c\xec\x08\xe7\x9d\xb8\x8a\x21\x46\x3e\x77\x80\x8c\xb2\xd8\xd0\xa1\x79\xac\xb3\x14\x83\xdd\x1f\x0b\xed\x82\xcf\xd1\x66\xa8\x05\x6f\xdf\x5d\x29\x8e\x93\xdb\xec\x47\x23\xbf\x17\x6e\xdd\x5c\x6d\x49\x54\x2b\xf4\x0b\x8a\xb6\xd6\x1a\xca\x00\x1e\x56\x44\x62\x97\x65\x63\xca\x71\x74\x79\xe3\x3d\x59\x7c\xfc\x12\xc1\x2d\x9a\x51\x7a\xa0\x0b\x13\x0b\xdd\x39\x82\x2e\x32\x5c\xaf\xfb\x1c\x81\x5e\x3b\xa1\x17\xe7\x12\xe1\x82\x8e\xf1\x21\x2d\x8f\x08\x04\xbc\xa5\xd7\x10\x0a\x29\xe6\x5c\xf2\x5d\xbf\xb2\xad\xea\x9d\x8d\x1c\x5f\x8b\x4c\x8a\xff\x47\x30\x55\x82\x52\xaa\x04\x25\x75\x2f\x05\x04\xe0\x45\x29\x28\xea\xb8\x63\xb5\x36\x21\xc6\x96\x78\x18\xe6\xdd\x2d\x86\xfc\x39\x1c\x0f\x1d\x24\x65\xc6\xab\x39\x75\xe7\x44\x40\x04\x61\x97\xa1\x29\x19\xcf\xc8\x07\x25\x48\x67\xf0\x68\x08\x98\x76\xd9\x99\x91\x1f\xfa\xce\xe6\xb6\xbe\xb3\xa8\x58\x4b\xfd\x1d\x57\x4e\x6a\x7b\x6a\xd6\x29\xa6\x42\x2f\x4b\x07\xe1\xf4\x42\xfd\xce\xda\xb4\x57\xe2\x27\x8a\xd3\x2f\x97\x02\xc7\x9a\x8b\xad\x98\x61\xe4\x0b\xca\xe4\x08\x33\x92\x8c\x5f\x67\xce\x97\x0c\x3c\x0d\x70\x2b\xf3\x0a\xf5\xbc\xc2\x22\x15\xd3\xcb\x35\x42\x67\x93\x2f\xbd\xc6\x17\x14\xfc\x27\x6d\xe7\x2d\x75\xa2\xbb\x8f\x99\xfb\x5a\xc0\xab\xcc\x3d\x14\xf0\xa9\xdb\x36\x74\xe4\x08\x9b\x1d\xa1\x5b\xb5\xed\x51\xf0\x1d\x81\xa9\xa3\x84\xce\x3a\x05\xde\x9e\x23\x74\xea\x28\x61\x33\x35\xdb\xf3\xcc\xfd\x22\xe0\x5d\xe6\xbe\x15\x90\xc4\x6d\x87\x7e\x4e\xde\x29\x81\x7d\x84\x1b\xfc\xfb\x37\xfe\x7c\xf4\x54\xab\xb0\x0a\x8b\x3e\xa6\x3f\xc2\x96\xed\x2d\x4c\x0f\x6a\xfa\x6d\x3f\xc4\x5f\x63\xb9\x31\x72\x24\x5a\xc4\xce\x33\x9d\x3e\xb4\xa6\x78\x12\x74\x3c\x10\xd5\x9a\x27\x0b\x0a\x22\xee\x56\x06\xaa\x61\x1f\xe1\xeb\xc7\x33\x92\xc4\x80\x63\x62\x24\x83\x01\xa5\x24\x2e\x60\x51\xc6\x6b\x1d\xe6\x38\x7a\xfe\x73\xed\xd6\xd0\x96\x86\x1c\x63\x99\x5e\xa4\x60\x32\x8a\x3e\x13\x75\x54\xa7\xa6\xce\x4c\x9a\x22\x9d\xc9\x5f\xd2\x3f\xcb\x07\x92\x7a\xaa\x22\xed\x1c\xff\x29\x2b\x53\x57\xf2\x78\x7d\x8a\xc0\x7a\x75\x03\xd3\x88\x81\x41\x71\xa7\xe0\xa3\x53\xae\x2b\xe1\x25\x75\x67\x44\xc4\xe0\xeb\x6a\x87\x51\x48\xd2\xca\x51\xa3\xf8\xaa\x1b\xc2\x63\x60\x08\x08\x36\x3b\x1a\x90\x74\x83\x61\xc2\x70\x60\xb6\x4f\x8b\x7a\x05\xb6\x07\x69\x7b\xa2\x28\xc4\xbd\xba\x97\x5f\xeb\x93\x11\xa9\x96\x5e\x67\x9f\x50\xb3\x7a\x56\xc6\xe3\xb4\xaf\x2b\x53\xcb\xf4\x2c\x37\x1b\x21\x23\x82\xa9\xa1\xf0\xc5\x5a\x06\x7b\x56\xcb\xd4\xc1\x31\x24\xbe\xf9\x74\xb9\xc8\x39\x0a\x67\x7a\x99\x53\xd0\x11\xc4\xaf\x3b\x7d\x6c\xb8\xfb\x8b\xbd\xc7\x53\x46\x81\x9d\x3b\x09\xb0\x91\x92\x7e\x30\xf9\x30\x33\xf7\x3d\xae\x6e\x49\x49\xc1\xdf\x71\x04\x78\x89\xbe\xbf\x68\x26\xfb\xd7\x20\xf9\xa4\x4c\xb3\x55\x73\x49\xc4\x73\x21\x2a\x7e\x5e\x9f\xa5\xcd\xa1\xae\x51\x46\xc7\xb8\x62\xdc\xf6\x77\x80\xdb\x1e\xc3\x8c\x3b\xaf\x32\xed\x8b\x45\x21\x51\x1f\xa7\xfa\xa3\x36\x71\xb5\x7f\x82\x9c\xec\xc7\x0c\x9e\x34\x9f\x78\xfa\xa4\xed\x01\xf6\xbe\x78\x60\xb3\xf6\x40\x48\xf2\xaa\xc7\xb9\x1a\x97\xab\xab\x11\x1c\x10\x01\xc3\x7a\x3e\x8d\xce\x9e\x38\xe6\x68\x58\x2e\x80\x7a\x46\x7b\x0e\x29\xee\x12\x33\xc7\x0b\xb8\x02\x45\x7a\x62\x77\x29\xef\xd9\x3b\xa9\x3a\xfc\x9d\x24\x5e\x9e\x49\xe2\xe5\x67\x8a\x79\xf8\xd2\x92\x2b\xc8\xfc\xf3\x32\x82\x21\xb4\x54\xbf\xa8\xa5\x9e\x16\x51\x9b\x8b\xe7\x4e\x4e\x92\x0d\x44\x23\x38\x12\x8b\xc1\x0b\x29\xa6\xa3\xbe\xc2\x77\x17\xb9\x8d\x4c\x42\x1e\x3f\x2e\x13\xf2\x7c\x11\x14\x0e\x32\x32\x95\xc4\x3a\x13\x69\x72\xd1\x0b\x72\x81\xf6\xff\x9e\xae\x98\xac\xb3\x44\xc7\x6b\x7d\x7f\x59\xe0\x4c\x53\xf0\x3e\x3b\x09\xca\xc0\x51\x6c\x92\xdc\x84\xb7\x3e\x46\x30\x3d\x26\x0a\xc2\x76\x7f\x7c\xa1\x4b\xa3\x3a\x51\x8c\xe3\x78\x8d\xc7\x65\x6b\xec\xa9\x5e\xfa\x8c\x11\xe6\xe2\x7e\x72\x75\x2d\x6d\x76\x86\xe2\x76\xbe\xca\x71\xcd\xc9\xcb\x0c\xde\x64\x28\x0a\x34\x38\x2f\x69\x67\xb6\xf7\xf9\x59\xe2\x4a\x46\xea\xc9\xde\x14\x3b\xa7\xdb\xd0\x51\x90\xd4\xe8\xaa\x84\x5f\x99\x33\x23\x69\x0c\x39\x48\x3b\x43\x25\x2a\xfe\x54\x54\xd2\x3b\xa8\xf1\xc9\xa6\xf8\x08\xfa\x16\xe3\x14\xbd\x03\x9c\x22\x4e\x98\xfd\x7f\x31\x55\x76\x56\x4d\x95\x9d\xd5\xf8\xf1\xae\xa9\xfa\xae\x1f\xeb\xa9\x92\x5c\x4f\x2e\xcf\xc0\x47\xef\x20\xf5\x56\x5c\x73\xe7\x2a\x43\x15\x54\xdb\x7b\xd9\xf2\x7b\xf3\xe5\xf7\x6e\x39\xcd\x47\xc2\x18\xfc\xb8\xf6\x4c\x18\xc3\xfb\xac\x9a\x0e\x3e\xad\x17\x3c\x8c\x21\x6b\xac\xf8\xf6\xd2\x70\xec\x54\xbf\x33\xd1\xec\xcb\x69\x8d\x8d\x5c\xe9\x16\xc6\x10\x34\x7a\x3d\x5a\xee\x75\xbc\x34\xd8\x71\xd9\xed\xf1\x6a\xb7\x72\xb0\xaa\xd7\x13\x47\x07\x4d\xae\xec\xf7\x01\x91\xf6\x54\x89\x6d\xf8\xe7\xaa\x53\x7d\xf6\x0d\xd7\x00\xbf\x1f\x57\xa7\x92\x12\x50\x4e\x58\x62\xf3\xbf\x91\x62\x75\xb4\x6e\x5f\xe8\x38\x24\xbd\x94\xfa\xb7\x69\x49\xca\x16\x3f\x86\x65\xcb\xc1\x8c\x20\x14\x1a\xfd\xeb\x2a\x54\xf9\x6e\x6a\xfb\x6a\x8f\x38\xc6\x80\x7a\x07\x8e\x70\x53\x9b\x19\x23\x42\x61\x70\x49\x5d\xe2\xd7\xe1\x49\x43\x8d\xfa\x60\x25\x2a\xf9\xea\xf4\xfa\xee\xe7\x9c\xd4\x0e\xf0\xf2\x8b\x8c\xbd\x23\x05\x9f\x6a\x3f\xa1\x15\x65\x37\x76\x33\xa6\x8b\x05\x85\x2c\x5e\x17\xdb\x52\x8f\x22\xd0\xfa\xb0\x19\xd9\xcd\x00\xa3\x11\x84\xcd\xb6\xcb\xf4\xb3\x0d\xcf\xdb\xbe\x33\x43\x4c\xf5\x8d\x02\xdb\x76\xae\xf1\x7a\x9b\x82\xf7\xde\x39\xe7\xc4\xda\x49\xf3\x38\xe8\x25\xa9\xec\x65\xb9\x37\x89\x24\x2a\x2d\x15\x32\x85\xa2\x40\x6d\x2f\xca\xb0\x7d\xce\x65\x0f\xd3\xb7\xdb\x56\x11\x19\x52\xe6\xb2\x6d\x7a\x35\xbf\x77\xf2\xb4\xf4\xf4\xad\x5c\x9b\x5f\xe6\xf0\x05\x19\x36\x99\x61\xc2\x72\x0a\x27\x19\x61\x0a\x72\xb5\x23\xf0\x0b\x74\x04\xc6\x1b\x35\x6f\x75\xed\xde\xec\xbb\x5b\xf7\x5c\x97\x60\x64\x84\xda\x8a\x83\xd4\xa9\xfc\xbc\xe5\x46\xbd\xd8\xae\xb5\x11\xd7\x8e\x74\x35\xa7\x78\x81\xc9\xa1\xcc\x11\xd1\x50\x9d\xd4\x5d\xb2\x85\x9e\x86\x2e\x17\x4d\xbe\x19\xa7\x74\xdb\xbb\x82\x54\x9d\x08\x9c\xfc\xe7\xac\xc5\x27\xfe\x17\xdb\x41\x43\x19\xd6\x7b\xd4\xa5\x1e\x91\x96\xb2\xbe\xa2\x35\x6c\xdb\x99\x93\x9d\xcc\x64\x6a\xf0\x21\xb1\x03\x0a\xbe\x92\x17\xfc\x3d\xb5\x0f\x51\xba\x68\x0d\x33\x13\x30\x27\x47\x6a\xa5\x74\x38\x08\x4e\xeb\x23\x2e\xe1\x8a\x6f\xf8\xd6\x3d\x23\x5c\x8f\xd5\x63\x07\xa9\x92\x64\x5b\x26\x85\xac\x80\x60\xa0\xc9\x8f\x5a\x48\x74\xe6\x2b\xa7\x49\x3c\x97\x84\xae\xba\xed\x2b\x0c\x6f\xb3\x53\xf0\xd5\x9f\x63\x48\xd5\x9f\x33\x88\x0d\xc4\x7f\xf2\x48\xe6\x86\xe8\xf3\x47\x21\xac\x6e\xa6\xea\xb7\xb1\xfd\xf9\x85\xed\x2f\x2f\x6d\x7f\x31\x84\xab\x86\x3e\x3c\xae\x19\xe8\xb4\xd4\xa5\xb5\x4f\x51\x7e\xcf\x57\x47\xcd\xab\xd9\xfa\xb2\xd2\xd6\x57\x5f\x40\x61\x7b\xef\x17\x7a\xef\x72\xa9\x40\xe8\x0b\x27\x47\x1e\xad\xb9\x99\x64\x6d\x87\x25\x5b\x3d\x2c\x6f\xf4\xa1\x60\x09\x82\x7c\x10\x65\xd7\x31\x9b\xf7\x58\x18\xea\xfc\x3b\x58\x9e\x3a\x5b\x7b\x34\xa0\xe3\xc0\x99\x23\xc3\xdc\x6c\xd5\x4b\xff\x8d\x3e\x2e\xd5\x41\xf9\x51\x1c\x14\x8c\xf7\x88\x99\x12\x19\xae\xe8\x6a\x6a\x87\x6a\x80\x64\x4d\x50\xa3\xea\xb1\xb3\x1a\x68\xb4\x32\x46\x84\x30\x30\x23\x9e\xa6\x15\x25\x9e\x88\xd2\xa5\x50\xb4\xa1\x51\x65\xcc\xc8\x8b\xac\xec\x68\x4f\x57\x42\x5f\xd4\x50\x1c\xd7\x7c\x1b\x22\xda\x08\x2e\x64\x55\xd4\x87\x5e\xaa\xc8\x65\x55\xbd\xa5\x2a\x4c\x03\x43\xf2\x15\x78\x2e\xad\xcf\x07\xbd\x3e\x91\x29\xa1\x10\x82\x07\x19\xa8\xe3\x1d\xc7\xeb\xd3\x5e\xed\xee\xbd\xdf\x3b\xd9\x5b\xce\x7c\x15\xc4\xb5\x30\x00\x6d\x28\x34\x31\x00\xd3\xf8\x5f\x33\xdb\xd9\x9e\xdf\x61\xb9\x8b\x63\x10\x10\xc4\xda\x82\xd2\xff\x57\x86\x6d\x49\x94\xb4\x62\x12\xdc\x4f\x09\x5a\x05\xd5\xe0\x93\xce\x15\xb8\xd0\x69\xa7\xbc\x8f\x3a\xfa\xe1\x32\x6e\x75\x0d\xde\x63\x3a\x8b\x7f\x11\x9f\x79\xe9\x7c\x12\x24\xa1\xc0\x6e\x9c\x04\xbc\x13\x53\x9f\x27\xee\x74\x0c\x5c\x2d\x6e\x9d\xe7\x85\x31\xbd\x01\x79\x51\xda\xd0\xca\xe6\x69\x93\x42\x9e\x9b\xf2\x20\x0b\x0a\xd7\xb1\xbb\x4b\xfe\x1a\xc1\x26\x0c\xd5\xf6\x74\x29\x20\x5a\x2a\xbf\x37\x80\xea\xc6\x99\x91\x8b\xb8\x5d\x39\xfd\x8d\xc3\x65\xac\x3e\xf7\x3a\xa6\x0b\x48\x1a\xb1\xa1\x2b\xe7\xee\x9b\x63\x02\xbf\x34\x0c\x7b\x6f\x10\xe1\xde\xe8\xe3\x3c\x27\x7d\xe4\x1a\xe1\x66\xf5\xd3\x0b\xa2\xf4\x46\x21\x38\x23\x0c\xd8\x9e\x4f\x57\x63\x3e\x35\x67\xeb\x2f\x13\xaa\xe2\xe1\xda\xdb\x34\xad\x9d\x93\x69\x8c\x2e\x09\x53\x49\x6e\x50\x78\x1a\x57\x54\x92\xd7\xa9\xa4\x45\x9d\x83\xb4\x22\xb2\xdb\x86\x1e\xae\x9c\xca\x14\xc3\xfd\x53\xcc\x8f\x81\x80\x37\x57\x24\xd1\xa7\xa8\x0d\x39\x0f\x1b\x83\x02\xc6\x64\x45\x45\x4c\x96\xef\xb2\x95\x98\xac\x94\x82\x3a\x25\x4e\xcb\x61\x8f\x34\x81\x5e\x09\xd6\x5b\x89\x1f\x53\xf0\x30\x8f\xd7\xb8\x42\x75\xef\xfe\x0a\xaa\x1c\xdd\x8a\x2a\xb7\x57\x77\x0d\xc3\x7b\x57\x71\x69\x9d\x0c\xd7\xb0\xaa\xf7\xce\xc1\x72\x6e\xfa\x19\xa7\x8e\xf6\x55\x5b\x9e\x13\x6e\xe8\x71\x81\xe5\xbe\x33\x8d\xfc\xa5\x42\xfe\xbc\x40\xfe\x28\xf9\xd7\x6d\x09\x79\x4b\xcc\x97\x9a\xdd\x08\xc1\xef\x28\x03\x09\x39\x3c\x67\xb5\x78\xae\x75\x4f\x54\x7b\xb4\xcc\x4d\xe5\x3a\x2a\xeb\xad\x58\x5b\x72\xf4\xd0\x49\x80\x9d\x38\x12\xbc\x33\x87\x83\xf7\x45\x63\x8a\xd7\xc6\xb1\x24\x15\xd1\x45\x94\xb0\x78\x5d\x99\xd8\x6b\xe3\xc7\x71\xb5\xa6\xde\x2f\xfa\xc2\xfc\x50\x6f\x39\xd4\x2f\x38\xec\x8c\xf1\x60\xaf\x1c\x01\xa6\xf6\x2c\x7c\x31\xf3\x60\x41\x20\x78\x96\xb5\x3b\xc3\x1c\xa2\xb8\x81\x7a\x95\xf5\xfe\x2f\x82\xb3\x60\xde\xe6\xfd\x92\x71\x29\xe3\x86\x93\x4b\xe1\xff\x12\x44\x19\xf3\xe2\x7f\xab\x7a\xef\x17\xe3\xfd\x73\xcd\xd1\xd9\xe4\x4c\x90\xfd\x94\x7c\x51\x42\x51\x51\x3a\xa4\xf0\x74\x39\x14\xba\xce\x88\xfe\xbc\xaa\xbe\x48\xe1\xf2\xa3\xbe\x72\xbd\xab\xc7\x2f\xf6\xc1\x91\xc0\xf6\x9d\x1c\xd8\x81\xc3\x81\x3d\x71\x18\x78\xbb\x6a\x4d\xcf\xf5\x9a\xee\xe8\x25\xbd\x48\x3f\x71\x91\x45\x18\x7f\x61\x16\xd5\xcb\xa3\x38\xd8\xd5\xae\x44\xf5\x5b\xa7\x19\x17\xb5\x5b\x82\x25\xfe\x65\xbd\x84\xca\x34\x5a\x1e\x67\x5a\x1b\xb8\xd8\x1f\x9c\xfd\x4d\x5c\xb8\xfa\xc8\x48\x7d\xe0\x61\xe1\xcb\x93\x84\xd1\x85\x05\xaf\xc5\xd2\xf3\x6f\x92\x30\xb5\x60\xc7\xf4\x89\xf3\x0c\x93\x97\x7d\x11\x58\x5a\x45\x8f\x09\x7b\xf1\x1d\x22\x65\x0a\xee\x40\x87\x4b\x7f\x0e\x21\x81\x9b\x78\x99\x2e\x0b\x45\x97\xb5\x9f\xf6\xf7\x78\x9d\xc5\x4d\x8b\x1b\x7b\x31\x94\xbc\xfd\x31\x83\x1f\x8a\xb7\x2f\x10\x84\x77\xe8\xfc\xf2\xb0\x56\xc5\xc2\xa0\x3d\x0a\xcf\xe3\xee\x4c\x72\x8f\x75\xb6\x9d\xed\x55\xcb\xe8\x43\x83\x2d\x32\x72\xe0\xc1\x5c\x1d\x72\x6f\x0b\x52\xa4\x2c\x1c\x24\xd5\x09\x90\x9a\x58\x61\xcb\xc1\x24\x2f\xb9\x93\x82\x7f\xea\xfc\xe4\x04\x27\xc0\x96\xd9\x40\xdf\xcd\xc8\x2c\x86\x1b\x44\x1c\xe7\x66\x4c\x85\x17\x80\xd5\x4d\x66\x66\xcc\x62\xb0\x97\x6a\x30\xf0\xcf\x1d\xbf\x0a\x7e\x7d\x8d\x12\x61\xd3\x17\xa1\x78\xf0\xd4\x79\xae\x59\xc0\x92\xc7\xff\xc1\x89\x09\x90\xe2\x4b\x81\xca\x85\x5c\xa7\x88\xe6\x9c\xcc\x63\x30\xa9\xaf\xd3\x85\x9a\xe2\x97\xce\xa9\x9d\x3a\x1f\xf5\xac\xbe\xd4\x67\x75\x58\x9b\xd5\xd3\xca\x86\xb7\xfa\xf0\x0b\x4e\x22\x5a\xcc\x10\xb7\x73\x0f\x0b\xaa\x46\x5a\x6c\xdc\x51\xcd\x95\xd8\xd6\x31\xc8\x87\xfa\x20\xa5\x28\xf3\x56\x3f\x4b\xdb\x52\x31\xe8\xe7\xbe\x2f\x73\xe8\x9b\xed\xd1\xda\x49\xc5\x83\x8d\xb6\xea\x5d\xae\x52\x52\x6f\xdb\x6e\x7f\x5c\xd6\x52\x1c\x34\x93\x94\xf6\x66\xe4\xbb\x91\x1a\x96\x12\x19\x84\x1a\xe4\x34\x43\xe1\x6d\xa9\x81\xf2\x02\xe4\xc2\x36\x90\x43\x63\x5f\x09\x64\x5b\x4e\xa8\xe1\x4b\x0f\xe0\x9f\xeb\x01\x0c\x7c\xad\x0e\xe0\x9f\x9b\x01\x56\x21\x0a\xa7\xe3\x69\x88\x30\xa3\x19\x58\xf0\x56\x87\xf9\xe2\x78\xed\x20\xb0\xe9\x78\xee\x0d\xc9\xca\x21\x3e\x17\x73\x69\x19\xe4\xb3\x19\xa4\x3c\x31\x0f\x9b\x7c\xc4\xd3\x15\x5e\x64\x65\x6f\xa7\x2b\x5d\x1e\x37\xbb\xc4\x2b\x5d\x9a\x21\xe3\x7e\x54\xeb\xd2\xce\x5d\xf9\xe9\x32\x77\x75\x1c\xaf\x2f\xc5\x37\x73\x38\xcc\x1d\x09\xb9\xae\xaf\x94\xc3\x4f\x4d\x13\xae\xe2\xf6\xe0\x36\xef\xfe\x7d\x62\x59\x9a\x3d\xd2\xfa\x41\xaf\x48\x8e\x6f\x33\xb8\x8a\x51\x5f\x42\x9d\xfd\x05\xec\x74\x62\xcd\x1b\x59\xd8\x12\xc7\x3a\x73\xaa\x53\x64\xd7\x37\x79\x6d\xdf\x2c\xbf\x5c\x8a\x79\xed\xd1\x80\xb7\x54\x92\xa2\x0b\x9f\x19\xc2\x5e\x96\xed\x59\x2c\xe0\x20\xee\x74\x9d\x7e\x23\xc1\x72\x2d\x53\xe7\x4c\xaa\xef\x92\x3a\xcf\xdc\x3d\x59\x24\x99\x4b\x5c\x75\xc9\x40\xba\x6f\x62\x34\x3a\x17\xd6\xba\x5a\xd5\x3c\xf1\x4c\x62\xf0\x77\xa2\xfa\x24\x4b\xe6\x38\xed\x8e\xa1\x93\xc7\xc2\x4e\xac\xb3\x6d\xd4\x13\xd2\x53\xf8\xd6\xb9\x46\x1d\xe9\xbe\xef\x25\x55\xf4\xb9\x29\x4c\xb4\x9c\x72\x5e\xd8\x79\x91\xf0\x8f\x56\x6b\x86\xc6\x8e\x67\x45\x0a\x2c\x6e\xb3\xfb\xf7\x97\x93\x82\x95\x7d\x12\x57\x2e\x16\x24\x21\x19\x39\x8e\x61\x7f\x25\xba\xf0\x8d\x26\xa3\xd5\x87\xea\x1d\xbf\x7f\x5f\x27\xbd\xb2\xd9\x38\xb1\x3d\x27\xa1\x0b\x25\xee\x49\x0a\x6a\x1d\x08\x96\x60\x3e\xa4\x76\x7f\xec\xa5\x0e\xc6\xee\x1f\xc4\xe0\xa5\x26\x93\xeb\x7d\x4b\x23\x34\xb5\xfb\x0f\x21\x97\x5a\xfc\x3d\x8a\xd7\x54\x0f\x28\x18\x9b\x0b\x47\xc2\x37\x05\xb8\x37\x0e\x87\x23\xc7\x87\x63\x87\xc1\x89\x93\xc3\x6b\x0d\xc4\x9f\xe3\x7f\xa1\xac\x96\x24\x65\xda\xd7\x73\x13\xa3\x85\x27\xe8\x64\x8d\x2a\xe2\x38\x06\x61\xff\x04\x61\xe7\x20\xec\x39\x08\x7b\x06\x85\x65\x69\x41\xe1\x6c\x89\xa5\x65\x45\x3d\x6b\x7f\x5d\x3d\xeb\xc4\xfe\x89\x7b\x99\x63\xf9\x80\x39\x96\x0f\x98\x3d\xab\xcb\xb5\x27\xb8\xe2\x9f\x29\xf8\x7a\x93\x2a\x86\x4f\xcf\xf7\xaa\xbd\x20\xe1\xe7\x18\xc3\x50\x8e\x53\x38\xc9\xe1\x67\x44\xf0\xf2\x8a\xc1\x24\x22\x56\xc8\xe2\x8c\x5b\x5a\xcb\x0e\xfb\x5d\x67\x26\xc1\x28\xb2\xee\x05\xc4\x3c\x35\x1c\xf4\x71\x5c\xc7\xd1\xf7\x66\x64\x5f\xcd\x86\x48\x57\xb4\x1a\x34\xe7\xb5\x24\x91\xf8\x8d\x6a\x55\xd4\x9a\x08\x48\xec\x19\x10\x34\xa4\x7e\xa6\x04\x7d\x7d\xe8\x57\xf4\x39\x29\xa2\xb0\x0f\xab\xcf\xf7\xd7\x94\x2d\x6b\x5d\x67\x2c\xd0\xed\x7d\x36\x18\x41\x23\x00\xac\xd3\x56\x11\x85\x0b\x92\x80\x4f\xc7\xc5\xc4\xca\xb2\x20\xe5\x26\x7c\x55\xc8\xaf\xcc\x01\xb9\x50\x82\x53\xf7\x7e\xb4\x56\xe3\xf0\x0c\x5e\x2d\x2a\xeb\xa1\x38\xb9\x80\x1d\x77\x46\xce\x04\x1c\xa9\x97\x1e\x8a\x5b\xfe\x39\x24\x45\x7a\x6e\x25\xba\x95\x89\x7e\xa9\xfe\xa5\x13\xfa\xa2\xdd\xe5\x73\x0c\x2b\x29\x7d\x0b\x28\x99\x60\x61\x49\x6a\x1e\x2a\x33\x03\x2b\xc9\xae\x96\x9e\x58\xff\xac\x52\x11\xeb\xdf\x26\x7c\x40\x3d\xdc\xa8\x62\x96\xfe\xbb\xbb\xa2\xcf\x90\x46\xba\x58\xb1\xd3\x4d\x89\x6f\xd0\x78\x89\x97\xf7\x35\x5e\x6e\x02\x92\xc9\xf6\x29\x28\x24\x7a\xbf\x88\x44\x00\xaa\x36\xcc\x98\xca\x23\xb0\x8e\x4f\x8e\xde\xec\xbf\xb2\xe0\x46\xa2\xcc\x8c\x40\x7b\x48\x2a\x7d\x9e\x5a\xbe\xfd\x58\x89\x1f\x87\xc4\xe2\x41\xa4\xad\xd6\x57\xcb\xd5\x36\x93\xca\x55\x34\x81\xdc\x95\x6b\xcf\x8f\x00\x0c\xb0\xc9\x8b\x13\x14\xad\x09\x70\x2f\x14\xef\x82\x82\x77\xe5\xcc\x31\x83\x50\x48\xb2\x90\x42\x10\x92\xfd\xa2\xb4\x7d\xd4\x3e\x6d\x0d\x21\x09\x9f\x59\x14\xe6\xe4\x0a\xa2\x25\x20\xc1\x1f\x45\x38\x85\xd9\x7f\x0d\x7c\x2d\xb3\xf6\xc8\x91\x82\xe4\x3d\x09\xf7\x46\xea\xdf\xe2\xff\x58\xcf\x47\xbf\xa7\xf6\xea\x25\x58\x34\x4b\xbd\x32\xbf\x2f\x42\x1d\xe3\x43\x52\xc8\x69\x14\x4e\x63\x97\x24\xa9\x8b\xfa\xa7\x33\x01\x2f\x39\xbc\xd6\xd1\x8d\x02\x9e\xa7\x70\x68\x2e\x5f\x70\x88\xcc\xe5\x47\x8e\xa3\xe0\xf5\x07\x0e\x6f\x8b\xeb\x9f\x1c\x76\xcc\xa5\x4e\x7e\xd7\x96\x8f\x1e\x79\x92\x05\xfd\x4a\xdb\xbc\x22\x10\xcb\xb5\xb1\x46\xe8\xf8\x92\xa0\x6c\xf5\x3e\x76\x5f\x0a\xd8\x45\x8f\x84\x47\x0b\x38\x8b\x8b\xc2\x8a\x3f\xf5\xd5\xf6\x02\xde\xc6\x77\x29\x1d\x74\x26\x3a\x1c\x8f\xfb\xc0\xdd\x1d\x1d\xb5\xeb\xce\xc8\xdb\x58\x3b\x1e\xf9\xa9\x2e\x99\x6a\x5d\x8b\x34\xc8\xf1\x21\x0b\x58\x8a\x99\xb7\x94\x6c\x38\x56\x44\xd9\x51\x04\xdc\x6f\x7b\xea\xa2\x91\x05\xbe\x78\x32\x6d\xc9\x5f\xc6\x6b\xce\x10\x8d\xd8\xde\x95\x32\x06\xbd\xeb\x74\xb1\x20\x5a\xd6\x7e\x1b\x2b\xa0\xad\xbd\x34\x68\x84\xaf\xcc\xcc\x4b\x73\xf7\x8c\x93\x62\xc6\x97\x52\x5e\x3b\x0f\x1e\xc4\xa9\xcf\xe2\xcb\x34\x93\xce\xd3\xe1\xd3\xad\x07\x56\x4d\x62\x7f\x1e\xc3\x1b\x1d\xa4\xdc\x77\x7f\x69\x23\xd9\x3e\xda\x96\x64\xa5\xcd\x8d\x52\xf0\x4e\xd0\x45\xa4\xf8\x9c\xe9\x2a\x2e\x0a\x56\x6f\xc5\xab\xb7\xb2\xd5\x5b\xde\xea\xad\x70\xf5\x56\xb4\x7a\xab\x05\x21\xb6\x50\x2e\xb6\x7a\x2b\x5f\xbd\xd5\x52\xa9\xb3\x85\xe9\x11\x6b\xf8\x20\x25\xbc\xc5\xe0\x6d\x3b\x29\x78\x8f\x9d\x08\xbc\xa7\x0e\x03\x3f\x72\x24\xf8\xb1\xc3\xc1\x4f\x1d\x01\x7e\xee\x78\xe0\x4f\x9d\x1c\xb0\x36\xab\xff\xd2\xf1\xc1\x3f\x75\x32\xf0\x3f\x3b\x01\xf8\xe7\x4e\x5f\x49\xdf\x53\xf0\x0e\x9d\x70\xd1\xf8\xdf\xb2\x39\xb3\xd8\xa0\x7b\x23\xf0\xde\xa1\x81\xaa\xcd\xdc\xb9\x5f\x33\x6d\xf6\x8b\x87\xb4\x3d\x8b\xcc\x48\x9c\x82\x04\x9f\x52\xc2\x29\x49\x29\x99\xa4\x54\x33\x9f\x24\xa7\x84\x51\x92\xa7\xd5\x7f\x09\x25\x3e\x25\x86\xc5\x7c\x29\xdc\x9f\x89\x1a\xfb\x4b\xe7\x59\xac\xd8\x78\xb1\x41\x2c\xc7\xda\xb8\x2a\xeb\xb7\xc0\xeb\x78\x8d\x17\xab\x11\x6f\xa4\x73\x42\x24\x9c\x90\x4a\xb4\x39\x8c\xbb\x99\x22\x5f\x91\x8b\x7d\xcf\xa4\xd5\xf9\x11\xbb\x87\x31\xb1\xfc\x98\x65\xd9\x3e\x9b\x70\x8b\xc2\x87\xb8\x88\x94\xf2\xae\x94\x88\xf5\x22\x76\xcf\x13\x62\x05\xd1\xd4\xa2\xf0\x52\xff\xc8\xae\x59\x62\x51\xf8\x18\xbb\x9f\x12\x78\x15\xbb\x33\xf2\x42\x31\xf2\x88\x3a\x5f\x9a\xab\x8f\x31\xb1\xde\xa7\x2c\x88\x92\x0b\xdb\xb6\x2d\xfa\x55\xe7\x63\xf9\x14\xbb\x89\x80\xf3\x0e\xc9\x4f\xa6\xa7\xd7\xd7\x5c\xec\xb0\x8c\x13\xba\x80\x77\xff\x8a\xe9\x48\xdb\x8d\x0a\x09\x7e\x59\xd7\xfe\x2a\x6e\xa2\x8b\x13\x56\x1a\x8b\x92\x00\x3f\xca\xcb\xa5\x4c\xd5\x67\x89\xe0\x8e\x99\x80\xa4\x7e\x30\xb2\x28\xf0\xc0\xcd\x05\xe4\x41\xf7\xc2\xf3\x00\x12\x30\x23\x08\xf4\x02\x63\x81\xcb\x04\xf8\x41\x8b\x2e\x31\x19\x5b\x21\x1b\x4c\xa2\x24\xcf\x2c\x47\x5d\x5e\xc7\x79\x66\xd5\x2a\x74\x06\x6a\x89\x4f\x11\x19\xfd\x88\x89\xe5\xc9\xa4\xe7\xc9\x64\x90\xe6\x32\x8e\x12\x3e\x88\x92\x30\xed\x79\xa9\x08\xb8\x18\x0c\x7b\x13\x31\x18\xf5\x26\xde\x60\x84\x74\x99\x05\x60\x4d\x98\xb8\x88\x92\x41\xcc\x43\x69\x81\x35\xd8\x12\x7c\xa2\x76\x48\xef\xa0\xc4\xc1\xd5\xb0\x21\x43\x85\xf2\x57\x0a\xfb\x45\xa5\xc7\x00\x01\x46\x46\x32\x56\xc0\x12\xe9\x15\xc8\x63\x8b\x42\xa8\xaf\x99\x45\xc1\x0b\xb4\x17\x5e\xe7\x62\x3c\xe7\x45\x5e\xb5\xce\x2e\x87\xa1\xe9\x42\x76\xc9\x5f\x05\x72\xb6\x00\xaf\x32\x75\xf9\x15\x03\x81\x83\xb5\xb5\x4f\x92\x7a\x4e\x7e\x93\xa5\x02\x19\x3e\xa6\x19\xbe\x67\xc2\xf5\x02\x92\x63\xd9\x86\xb1\x3e\x50\xcc\xee\x8f\x09\x46\x53\x94\x55\xb3\x12\xd7\xa4\x70\xbf\x96\x24\xa7\xfa\xb2\x2f\x89\xdc\xb0\x7a\x6a\xeb\x29\xc5\x6a\xb3\xad\x7d\xb0\x87\x68\xeb\x21\x28\x16\x70\xa8\xbf\xb5\xf1\xb6\xbe\x24\xc5\x44\x74\xf1\x9f\x1c\x5f\x56\x1b\x49\xbf\x60\xc3\x8c\xb6\x74\x5f\xdf\xc3\x5c\x25\x81\xdb\xca\x80\x14\x49\x84\xec\xec\x3a\x8e\x24\x79\xf0\xcf\x6c\xe3\xc1\x85\x12\xce\x02\xb3\xc7\x4c\x5c\x70\x69\x51\x98\xea\x8d\x95\x81\x45\xa1\x6f\xae\x2f\x2d\x0a\x13\x73\xad\xb8\xb9\xcb\xa0\xdb\x92\x9c\x60\xc0\x84\xcd\x86\x14\x7d\xc5\x0b\xd0\xdd\x93\x77\x81\xdd\x82\xc7\x6f\x05\xce\xe2\x8c\x28\x08\xdf\xb4\x34\x9c\x82\x42\x3c\xa8\xc4\x57\x20\xeb\x14\x2f\xbc\xf5\x4d\x8a\x03\x64\xa4\x9c\x69\xd7\xfb\xd4\x41\xec\x7e\xdd\x82\xc2\x85\x5e\x95\x58\x61\x85\xeb\xa5\x55\xe1\x50\xca\x20\xdd\x39\xf0\x45\x3d\x07\xbe\xe2\xd4\xc7\x07\x45\x69\x53\x2c\x6e\xe5\x1c\x60\x92\x08\x23\x11\xd6\xaa\x5e\xa0\xce\x43\xc0\x01\xd9\x07\xcd\x99\x53\x98\xad\x3d\x1c\xcd\x6a\x7b\x49\x19\x47\x14\x3c\x53\x5c\xd4\x2c\xd0\xfe\xfc\x36\xa7\x45\x55\xa0\xb9\xd9\x71\xe6\xe1\xe9\xbf\x09\xdc\x84\xc1\x5e\xd0\x15\xb8\x06\x89\x7b\x42\x08\x77\x67\xe4\x3a\xd0\x02\x1f\x97\xf0\x51\x92\x5a\x49\x0f\x5a\x4f\x45\xdd\x89\x0b\x7e\x94\xb8\x20\xa1\x98\x8f\x3a\xc4\xca\x04\x97\x4a\x6e\xc0\x80\x61\xaf\xc6\xa5\x5d\x04\x7a\xe7\x14\x9e\xbb\x4e\xb3\x48\x73\xa8\xc8\xe7\x47\xbe\xa5\x61\x8e\xc5\xd1\x45\x32\x88\x24\x9f\x64\x03\x0c\xd0\xee\xc5\x51\x26\x07\x3a\x69\xb9\xba\x5d\x01\xe0\xb5\x42\xa0\xde\x60\xbb\x02\xc1\x17\x71\x01\x12\xb3\xc1\x68\x88\xad\x9b\xbd\x60\x10\xc6\xfc\xa6\xb7\x32\x70\xf1\xd8\x0f\x25\x05\xc2\xf0\xcf\x43\xf4\x00\x7c\xab\x4e\xc2\xa7\x56\xbf\x82\x77\x68\xaa\x78\x82\x65\xa7\x50\xbe\xb9\x0c\x74\x52\x0f\x47\x41\x9a\x45\x81\x60\x26\xc8\x47\xd4\xee\x8f\xf5\x1d\xe7\x27\xd3\x5e\xf7\xaf\xf1\x1d\x27\xb9\x5a\x9b\x43\xdb\x0b\x6a\x5d\x66\x24\xbc\xdb\x31\xe8\x49\x7e\x23\xf1\x56\xf7\x99\xe3\x73\x3e\xc8\x62\x96\x5d\xb6\x1c\x84\x52\x42\x37\xf4\xfe\x82\x08\x0c\x90\x2a\x8e\xff\xbc\x1c\x0b\xa1\xa8\x57\x2e\xe1\x08\xc7\x41\xed\xd3\x19\xd3\x1b\xcc\xde\xd2\xea\xb3\x0d\x8f\x81\x1d\xde\x62\xd0\x81\x3e\x6f\xdf\x83\x5b\xa2\x31\xa4\xed\x8d\xbb\xdd\xda\xb5\x53\x69\x05\x3d\xd5\xe6\xaa\x25\x42\x80\xa8\xd3\xcf\x62\x49\x5e\xd6\xbb\xe9\x35\x9b\xe4\xf8\xdd\x86\xc2\xe6\x19\x17\x83\x8c\xc7\xdc\x57\x14\x36\x4a\x22\x19\xb1\xb8\x6c\x1d\x4c\xd2\x9f\x83\x5b\xba\xcc\xb8\xf7\x3d\x92\xb7\xf4\x32\xdb\xe6\xa7\xb1\x92\x6b\xac\xff\xf5\xd0\xf3\x87\x41\x89\x2e\x3f\xc6\x44\x6c\xfc\xc3\xb5\xfe\xb1\x91\x6c\xfc\xc3\xfa\x07\x6e\xc8\x6d\x08\x51\xe3\xc1\x7d\x46\x0e\x88\xd6\x4f\x42\x1a\x10\xeb\x25\xca\xd3\x3d\x6f\xde\x93\x97\x51\xd6\x8b\x99\xc7\xe3\xda\x5b\xac\x8d\x62\xc3\x17\x20\xa9\xd3\xb2\x44\xea\x35\x19\xf7\xd3\x24\x60\x62\xbe\xba\xa2\x6a\x8c\xfd\x54\xf6\x70\xc1\x4b\xf0\x01\xe6\xb2\xdf\xbf\x31\x2b\x6d\x8e\x81\x45\xee\xfa\x53\xf3\xb4\x3a\x35\x7e\xa0\xc3\x7c\x20\x77\xb1\x40\x14\xe4\xee\x08\xb3\x82\x5f\x29\xda\xb8\x61\xf5\x10\x07\x59\xce\xd2\xcf\xcc\x82\xdc\x6d\x4c\x7e\x12\xeb\xa9\x0e\xcb\x35\x9f\x5d\x46\x92\x0f\xb2\x6b\xe6\x73\x0b\xac\x24\x9d\x09\x76\x5d\xfb\x8e\x5c\xcf\x7d\x09\xa4\xf6\x9b\x98\x63\xe2\x0d\xb6\x0c\xc0\xfb\x12\x04\x9c\x10\x1f\x0b\x6a\x01\x1b\xcf\x48\x54\x6e\x50\x85\x95\xcc\x14\x8a\x23\x32\x23\x7b\x01\x56\xeb\x46\x8e\x40\x1f\x11\x7d\x1e\x9e\x07\x6b\x54\xc9\x11\x60\x00\x19\x84\x29\x84\xa8\x45\x38\x0e\xea\x7e\x1a\xfa\xe4\xe8\x78\x9a\xc4\x54\xf2\x49\xea\x2a\xfc\xfa\x27\x5c\xc7\x83\x87\x66\x42\x27\xb2\x0b\x77\x87\xe4\x7b\x80\x07\x32\x44\xe5\xff\x25\x6a\xe0\xdf\x60\x9d\xee\x05\xca\xe0\x75\x07\xef\x37\x90\xb8\x21\x0a\x3f\xaa\xe7\xb3\xe5\x21\x66\xe4\x79\x80\xb9\x7e\xf0\x03\x86\x6a\x80\x8a\x95\xb7\xf6\x53\xbd\x83\x1a\x80\xb2\x5e\x98\xe6\x49\x80\xbe\xc7\x4c\xdc\x22\x0c\x7d\x08\x8d\x30\x74\xa5\xf8\x71\x62\xf9\x97\xdc\xff\x8e\x27\x79\xc7\xf0\xf7\xc9\x75\xae\xf8\xa0\x37\x86\xb2\x6b\xd8\x87\x83\xa0\x72\x05\x34\xbc\x12\x94\x0f\x2b\xd8\x4d\x29\x7c\x33\xac\xd4\xfc\x5a\xd1\xcb\xa3\xa0\x5b\x9a\x2b\xe8\x96\x5a\xd9\x84\x4d\x91\x84\x54\xe8\xe6\x4d\xd9\x36\x91\x0a\x1c\x15\x4c\x6a\x8d\xea\xc0\x4f\x13\x29\xd2\xb8\xfc\xa9\x26\xe0\xa5\x37\xd5\xb3\x3b\xf8\xec\xb7\xc0\x7c\x19\xb6\x21\x11\x5c\x1e\x60\x50\x7c\xe6\x55\x50\x95\x81\xa3\x14\x3e\x30\xad\xc6\x97\xf0\x0e\xf3\x82\x03\x56\xcd\xae\xce\xc7\xca\x28\x41\xe4\xa3\x96\xe5\xf6\xbe\x01\xcf\x7c\x11\x5d\x23\x81\xae\xce\x4f\x62\x30\x89\x06\xe7\xcf\xc1\xfa\x18\xbd\xee\x55\x33\x15\x51\xea\xef\x57\x5d\xe2\x28\xf9\x5e\xe7\x2a\x79\xc5\x23\x1a\x94\xca\xfc\xef\x0a\x8a\x92\xc0\x02\x4b\x0a\x96\x64\xd7\x4c\xa0\x96\xd2\x9c\xff\x30\x4d\x34\x2a\xbe\xe4\x22\xaa\x6e\xfb\xb9\xc8\x10\x09\x5f\xa7\x51\xa2\x75\x9c\xba\xc1\x60\x57\xc4\x15\x09\x37\x8b\x5f\x4c\x45\xa3\x5b\xb4\x67\xe0\x64\xf4\x57\x9f\x04\x77\x4c\xf3\xba\xaf\x61\xb6\x74\x17\xa2\x70\x1a\xb8\xff\xe0\xc9\xd4\xad\xeb\xe7\xfe\x01\xef\x35\x20\x46\xaa\xc7\x6e\xe0\x3e\x81\xb3\xc0\x1d\x6d\xc1\x4f\x05\xc3\x07\x52\xb3\x5f\x37\x12\xa6\x12\x43\xa2\xe1\xed\x1d\x04\xd9\x51\x29\xc8\x7e\x69\x3b\x09\x3a\x8f\x90\x71\x8e\x7d\xad\x7a\xa4\x29\x58\xdf\xf9\x7c\x27\x0d\xb8\x05\x98\x7e\x1b\x4f\xa7\x09\x45\x8b\xca\xb8\x31\x2f\xac\xc7\x8e\xc9\xb0\x8a\xee\x3a\x0c\xca\xe8\x2e\x66\xca\xad\xff\xd0\x87\x32\x9b\xb0\x58\x1d\xca\x0f\xfa\x3b\xf5\xcb\x29\xbc\x08\x3a\xb3\x5f\xfb\x67\x5a\xba\xbb\xd2\xb9\x53\x22\x2c\xa6\xc8\xde\x81\xef\x1e\x2a\x89\x10\x52\xf7\x94\xe9\x83\xf0\x2e\xd4\x89\x65\x45\x80\x69\x93\x7c\x6d\x6f\xf8\x19\x28\xaa\x12\xba\x17\xc4\xc7\x25\x33\x35\x11\x3e\x32\x40\x7e\xd9\xd4\xa0\xb0\x2c\xc7\xb7\xfb\x63\xeb\x92\x65\x83\x80\x25\x17\x5c\x58\x0e\xfe\xc8\x72\xdf\xe7\x59\x5d\xa6\xaf\x30\xab\x48\x67\xbd\x24\x1d\x5c\xe4\x52\x72\x91\x75\xf0\x94\x27\xc6\x41\xdf\x57\xef\x6b\x50\x17\x3f\x8d\x7b\xd6\x86\x28\xa5\xfd\x28\x19\xcc\xa2\x40\x5e\x5a\x20\xc7\xd6\xd6\x70\x78\x7d\x63\x39\xd6\x26\xfe\x6d\xe1\x6a\x5b\x5f\xaf\xce\x2c\x4f\xe4\x20\x93\x82\x4b\xff\xb2\xed\x39\xf5\x56\x44\x22\x03\x63\xfb\x59\xc6\x40\xef\x83\xf6\x1a\x84\x78\x1c\xc2\x54\x94\x78\x01\xb7\x51\x6d\xc1\x3b\x46\x1a\x41\x9e\xea\x4c\x9f\x05\xb5\x70\xd8\xd6\xed\x29\x8a\x2d\xed\x06\xd4\xd4\x64\xba\xe7\xba\x79\xf1\xd0\x0b\xa6\xfa\x3d\x4b\xdc\x03\xc2\x20\xaa\x85\x97\x19\x5f\x83\xfe\xf8\x5d\xe8\xcc\xc8\x49\x00\xf7\xd0\x06\x68\xb3\x92\xd2\xbc\x0b\x15\xd1\xf2\x49\x47\xf9\xd3\xdd\x80\x8e\xd5\xe8\x23\xea\x60\xcf\x73\x46\x5e\xb2\x16\x34\x58\x5b\xa4\x81\x27\x93\x6a\xa1\x56\x39\xb3\x6b\x11\x4d\x98\x98\x5b\xea\xa4\x93\x90\x42\xda\xc2\x72\x29\xae\x4e\x8e\x9b\x3b\xe1\xa7\xf1\x80\xe5\x32\xed\x35\xde\xa6\x88\xc7\x66\xdb\xf6\xb5\x6e\x5d\x78\x1b\xaf\xf8\x9e\x91\x57\xcc\x60\xaf\x56\x61\xc1\xe3\x71\xac\xa5\x85\x41\xba\x22\x2f\x98\xd8\x88\xda\x97\x54\xbc\x0c\xcc\xc8\x8f\x6a\x2c\x05\x1f\x8a\xcd\x5e\xe2\xb5\xab\xc5\xd8\x41\xca\xd2\x33\x40\x05\x3d\x6e\x5f\xd8\x56\x3b\xb3\x8b\x04\x00\xd9\xd1\x89\x81\x6d\x8f\x65\x1c\x31\x34\xe2\xe2\x97\x8c\x9c\x06\xb4\x1a\xfb\x34\xa8\x66\x67\x4a\x43\xbe\xbc\xab\x86\xf0\x63\x9b\x72\xaf\xd0\x88\x50\x3a\x2e\x33\xa0\x59\x2b\xca\x3d\x35\xe5\x40\xa4\xd7\x41\x3a\xd3\x87\x1f\x55\x71\x80\x48\xe9\x25\xc2\xa6\xa8\x4d\x52\x18\xc2\xf1\x6a\x2d\x8b\x51\xb1\x11\xe1\xa3\x5e\x10\x79\xbd\x89\xb7\xd9\x9b\x88\x56\xe9\xd5\xe7\x9a\x88\xad\x65\x23\xae\x02\x22\x90\x45\x90\x2d\x60\x7e\x5d\x03\x34\xb5\x47\x46\x97\x68\x66\xfa\xe9\xae\x24\xee\x5c\x91\xab\x77\x81\xbb\x3d\x84\x64\xaa\x88\x96\x98\xba\x5b\x4f\x40\x4e\xef\x58\xf5\xb8\xf0\x61\x29\xcb\x1e\x5f\xe8\xc2\x84\x25\x16\x51\x02\x33\xad\x17\x3f\xe6\xd3\x95\xe2\xc7\x05\xd5\x60\x5f\xd0\x6a\xec\x7d\x47\x2d\xa2\x17\xa3\x1a\xd1\x97\xe8\x73\xcf\xde\xa1\x9f\x7b\x10\x82\xa6\x0d\x88\x95\x3a\xc9\xa8\x9c\x16\x3a\x8d\x53\x89\xf9\x43\x73\xf4\x14\x15\x63\xe9\x39\xc5\x0e\x4b\x6d\x5c\x0d\x42\x25\xd4\xff\x0b\x23\x72\x1c\xad\x8d\xb4\xdc\x82\x9f\x9b\x55\xdb\x3a\x70\xb3\xec\xc2\xcd\xef\x2a\xdc\x1c\xfa\x24\x2a\x31\xb1\x98\xd6\xef\xa7\xe5\xfd\xa4\xba\x2f\xc6\xf8\xa1\xd2\x64\x71\x7f\xa9\xb1\x79\x8e\x2a\xbc\x62\x35\x8a\xc7\xce\xeb\x88\x5d\x16\x23\x44\x7e\x89\xd8\x7f\x06\x84\x61\x78\x40\x85\xdc\x4d\xa8\xa9\x5e\xde\x4f\x06\xb9\xb3\x1a\x72\x97\xde\x5a\xe4\x7e\x1e\xd0\xb1\x7a\xc3\x88\x3a\xd8\xf3\x9c\x11\xdf\x47\x6d\x4c\x8a\xef\x85\x19\xc9\x91\x39\xf4\xf3\xcc\x02\x8f\xab\x3d\xa5\xe0\xf9\x24\xc5\x87\xfe\x83\x64\x40\x20\x16\x48\x68\x3b\x29\x58\x50\xc8\xa7\x9d\x5c\x8f\x81\x5f\x5f\x42\xee\xde\x43\xc1\x5a\x42\x62\xfb\xaf\xa8\x12\xb3\x7f\x84\x85\x87\x22\x93\x44\x52\xc5\xbc\xe4\x6b\x58\x17\xcc\xb3\xd4\x22\xd2\x62\x68\xc9\xab\x00\xac\xbd\x04\x55\x3c\x9a\xeb\xd7\x92\x19\xfa\x7e\x08\x90\x7e\x3d\x46\x49\x8c\x2b\x21\x59\xc2\xdf\xe5\x84\xb2\x6e\x4e\x88\xb5\x70\x42\x4d\xfe\x87\x4f\x51\xf4\x05\x5c\x86\x9a\x86\x12\xb8\x92\x21\xee\x4e\x89\xde\x2b\xf1\xb0\xf7\x9d\xcf\x7b\x61\x2a\xca\x8f\x2e\xf4\x0b\x46\x27\xfd\x1f\x1a\xee\xdf\xa2\x73\xbe\xbf\xac\x88\xad\xde\x59\xbb\x6b\xd8\x0b\xc2\x5d\x92\xbb\x09\x55\x18\x2f\x71\x73\x85\xff\xea\xab\xac\xf8\x0c\x3f\x9d\x5c\xc7\x5c\xf2\xc1\x84\x27\x79\xcf\xda\x20\x24\xb7\xd9\xe6\xef\xdf\xb9\xed\xed\xd0\xfb\xf7\xd5\xd1\xb3\xb2\xcb\x74\xa6\x68\x9d\xc2\x76\x3e\xe1\x78\x6e\x28\x30\x7d\x39\xa2\x2d\x4c\x49\x49\x01\xd5\xa8\x95\xfa\xe3\x23\x22\x58\xad\x03\x2c\xe8\xb2\x5a\x59\xa9\x44\x8a\xa9\x71\x89\xf0\xa7\xeb\x89\x6f\x2b\x91\xad\x24\x43\xa7\xad\x7d\x9d\xb4\x77\xca\x48\xec\x13\x61\xfb\x47\x2b\xfa\x9f\xa4\x20\xd3\xb6\x37\x29\x2c\x69\x53\x53\x82\x28\x5a\x9d\xa6\xd0\x48\x3f\x51\x68\xbf\x2a\xef\xda\x59\x8a\xef\x46\xde\x52\xd0\x31\xb1\xfd\xa3\x45\x29\xe4\x7d\x94\x3a\x20\x1e\x83\x19\x9e\xad\x91\xa4\x15\xab\xa8\xb6\x16\x3f\x3a\x15\x60\x49\xe6\xbd\x49\x02\x7e\x83\x85\x59\x46\xb4\x58\x8b\x9a\x96\x5d\xf0\x98\xe9\x05\xec\x10\x7e\x97\xb7\xf8\x94\x91\x74\xaa\xa9\x8c\x56\x6c\x88\xc1\xf6\x9a\x25\xae\x40\xf4\xc8\x38\x8a\x39\x3d\x6b\x43\x7b\x29\xa1\x37\x89\xa8\x61\xc1\x70\xda\xed\xfd\xe2\xbd\xfd\xfd\x5b\xd8\xde\xce\x58\x01\xb6\x74\x05\x55\x88\x11\x6b\x2b\xbd\xc6\x1c\x90\x9a\x86\xa3\x53\xde\xf7\x7f\x89\x90\x4b\x43\xc8\xfd\x92\x6c\xcb\xbb\x3f\x2f\xf5\xb3\xeb\xb6\x02\x57\xa8\xb7\x7a\xde\xf0\x64\xe1\xa9\x0a\xaa\x53\x15\xe8\x53\xf5\x6f\xec\x52\xc5\x19\x34\xcb\x51\x2a\x36\x80\x23\x7d\x63\x53\x24\x86\x7d\x7f\x85\x29\xa8\x51\xcf\x77\x01\x1d\x4f\x7d\xe2\x53\xc7\xb0\x03\xea\x17\xd3\xbf\x92\x29\x1d\xc7\xbe\x96\xb5\x39\x74\x25\x03\xd4\x30\x9c\x53\x4a\x9d\x1b\x6f\x61\x60\xa6\x0e\x2e\x26\x00\xdb\x02\xcb\x8b\x53\xff\x7b\xa5\xae\x35\xf8\x7e\x34\x1c\xfe\x5f\x95\x52\xaa\x03\xc5\xf4\x96\x7e\x0d\x44\x74\x71\x29\x2b\xb4\xe3\x4f\x95\x58\x2a\x35\xbe\x71\x66\x24\x9a\xa2\x43\xb9\xf7\x93\x56\xc6\x65\x60\xe0\x2f\x28\x78\x6b\x68\xf0\x6b\xa4\xc1\xec\xa9\xb6\x44\x7f\xd3\xa6\xe8\xb9\x8e\xdb\x3c\xd1\x61\x31\x7b\x3a\x8f\xda\x2e\x9a\x27\xfc\x74\xbd\x32\xd9\x67\x22\xe8\xd5\xc9\x6f\xb3\x71\x70\xc9\x59\x50\x67\xe6\xa3\x3a\x80\xf5\x14\x90\x49\xe6\x65\xbd\x5a\x5f\xbc\x51\x3c\x70\x43\x3e\x07\x30\x04\x5f\xa3\x90\x03\x86\x45\xe7\xcc\x49\x7c\x69\x3c\xed\x14\x99\xc0\x7e\xa3\xd6\x7e\xc2\x66\x17\x63\x0b\xfd\x3f\x7b\x44\x73\x04\xd4\x72\xf4\x8d\x42\xdc\xfb\x14\x2f\x55\xb5\x9b\x91\x70\xaa\x56\xf7\x06\xb3\x3f\xcc\xc9\x51\x00\x85\xc0\x18\x58\x20\xec\x13\x38\x62\xc5\xfd\xca\xf0\x04\xc2\x3e\x86\x6f\xac\xa0\x5c\x2b\x4b\x61\x80\x43\x7f\x98\x3f\xae\xde\x2a\x8a\xb7\xe6\x53\xe0\xa0\xe6\x8b\x7b\x5c\x34\x27\x45\xf3\x8b\x00\x7e\xf9\x67\xce\xbd\x21\x42\x63\xfd\x35\xfb\x5d\xec\x5b\x21\x33\x57\x06\x90\x15\xdf\x8c\x2d\x4d\x40\xb4\x1d\x63\xa4\x04\xa0\x7b\xc9\xc2\x50\xc4\x64\xbc\xce\xf0\xbd\x55\x17\xa8\x77\xd2\x38\x66\xd7\x19\xef\xb1\x38\x36\xba\x70\x8b\x7e\x75\xd6\x18\xb2\x97\x1e\xd7\x8e\x79\xcb\x0f\x17\x1f\xf8\x2e\x86\x39\x39\x0e\x20\x85\x48\xf1\x49\xd2\xa0\xd9\x6c\x8a\x0a\xb8\xcb\x91\x45\x21\x9e\x2e\xb9\x02\x65\xd3\xca\x15\x28\x49\x65\xa1\x94\x37\x23\x06\x53\x53\x1b\x78\x3a\x35\xc9\xf5\xfa\x78\x31\x1a\x2e\x60\x82\x57\x4f\x16\x70\x89\x17\xdb\x0b\xb8\x98\x76\x9a\xf9\x6a\x62\xdf\xf0\x4f\x17\x73\x2d\xeb\x3c\xcb\x8a\x03\x37\x07\xe7\x54\x92\x5c\x1f\x52\xdf\x4d\x20\x75\x05\x44\xae\x84\xd0\xe5\xe0\xb9\x68\x82\x61\x90\x53\xc8\x5c\x93\x4e\x55\x60\xad\xce\x67\xba\x2c\x79\x0a\xd2\x8d\x80\xbb\x21\xe4\xae\x07\xcc\xcd\x30\xc2\x7c\xba\x36\xe6\xa5\x17\x92\x8b\x29\x3a\xc3\x9f\x4b\x2c\x34\x82\xd1\xb5\xfb\x30\x27\x87\x19\x26\x67\xd3\xa9\xe4\x66\xd3\x2e\x07\x27\x53\x64\xa9\x51\x2d\x6f\xb4\xbd\x3d\xa4\x74\xa5\x9e\x4e\x23\x38\x79\xbb\x59\xa9\xa8\x11\x91\xfe\xa8\x11\x8f\x35\x6c\xd6\x27\x6a\x3a\x4b\x6d\xa2\xf1\xbf\x93\x9e\x62\xd0\xff\x9f\x8f\xc7\xc2\x99\x91\xf9\x54\x9d\x20\x0f\xeb\x43\xc1\x8c\x7c\xc6\x20\x47\x44\x39\xfa\x9e\xd1\xa0\xdc\xe0\xbe\x6e\x2d\x60\x6f\x7a\xab\x87\xdb\xef\xdf\x26\x1e\xc6\x38\xab\x2f\xe5\x6a\x5c\x50\xf8\xbe\x34\x84\xc4\xea\x19\xc6\xc0\x7b\x41\xe6\x3e\x49\x28\xcc\x7d\x05\x0c\x63\x0b\xad\x97\x93\x34\x91\x97\x8a\x0d\x85\xbc\x5b\xcb\x5d\xe6\x00\x4d\xca\xb4\x94\x82\xae\x4d\x8d\x7a\x2f\xb1\xfb\xf7\xef\xab\xa9\xce\x48\x8e\x91\x4a\x9c\x8e\x85\x63\x59\x0b\xcd\x0e\xe0\x84\x23\xb0\x7a\x5c\x1d\x02\x54\x15\xe0\xad\x1f\x60\xf5\x26\x69\x9e\xf1\x14\x1d\xdf\x51\xe2\xc7\x86\x39\x58\x3d\x23\xe5\x40\xd2\x9e\x52\x89\xcd\x71\xd0\xae\x74\x4a\x96\x55\x9a\xd7\x3c\xf4\x2d\x39\x20\x66\x6e\x38\x3b\xb5\x53\x98\x81\x0b\x9f\x17\x36\xfb\xfd\x7b\x13\x53\x63\x7a\xd5\xf3\xe6\xa2\xe7\x71\x39\xe3\x3c\xb1\x16\x84\x16\x1c\xd2\x01\xc1\x44\xeb\x0a\x05\xef\x4d\xa1\xb3\x30\x51\x04\x98\xaa\xa0\x9a\x6c\xab\x62\x22\x60\x92\xf7\x3c\xe6\x7f\xb7\x36\x08\xb3\x99\xfa\xc7\xdb\x48\x68\xab\x4c\xa0\xba\x86\x22\x4d\xa4\xb5\x91\x6e\x90\x68\x83\xf8\x1b\x26\xf7\x93\x92\xc0\xab\xb5\x54\x52\xb8\xe2\xb1\x4d\xd8\x27\xfa\xf7\x4c\x2b\x26\xf2\x4a\x81\xd2\x19\x66\x37\xe6\xb4\xc6\x38\x3e\x9f\xae\xd3\xa1\x2d\x11\xe0\xfd\xc2\x1a\xfb\x7d\x5a\x14\xd1\x31\x83\x1c\x4f\xbb\xaa\x24\x29\xa4\xe5\x12\xee\x4e\x18\x72\x9e\x0a\xa1\x90\xeb\x29\x8c\x46\x80\x29\x79\x39\x90\xdc\x9d\x29\x76\x68\x36\x35\x53\x2b\x93\x0d\x3f\x1e\xe4\xc5\x6c\x21\x77\xeb\x49\x87\x95\x2c\x5e\x3d\x93\x63\xce\xdf\x32\x45\x31\x79\xac\xce\xcf\x78\xe8\x48\xaa\x5b\x41\x2e\xbf\x53\xaa\x7b\x7c\xf9\x5e\xae\x00\x44\x7b\x96\x62\x4c\xa3\xde\xf6\xf9\x14\x18\xec\xd3\x2e\xab\xc5\x55\x9e\xc9\x28\x9c\x97\xd6\x82\xa6\x12\xb1\xe6\x3a\xc3\xf9\xf7\x1a\x57\x82\xcb\x78\xe3\xa3\x09\xe9\x38\x57\x3c\xea\x07\xe4\x54\x4f\x72\xc5\x94\x9e\x29\xba\x6e\x9d\x5c\xe6\x16\x58\x2f\x45\x64\x81\x75\xcc\xa4\x76\x00\x6c\x02\x06\xbe\x9a\x45\x89\xb1\xbf\x55\x00\x91\x4b\x84\x87\xcb\x29\xad\x19\xd1\x9f\x9b\x6d\x63\xc5\xb6\x5d\x21\x5e\x1a\x2e\x60\x67\x6a\x52\xfd\xbd\xd1\xf4\xcd\x53\xe3\x1d\xe8\xeb\x6b\x8b\xc2\xb7\x6e\x20\x51\xd2\x67\xbd\xe8\x2c\x16\x9c\x5d\xdb\xfd\x61\xb3\xfb\x67\xfd\xa2\x4c\x8a\x34\xb9\x50\xcc\xf6\x1a\x23\xf6\xfb\x36\x91\x8f\x24\x76\x7f\xbc\x9b\x3a\x1e\xa7\x3a\xb8\x07\x66\x24\xe2\x65\x55\xb0\x6e\xa3\x78\x51\xd1\xa4\x56\xcc\x84\x58\x7e\x99\xf8\xcb\x4f\x93\x29\x17\xb2\x97\x49\x11\xe1\xcc\x4e\xa6\xda\xf6\xf7\xc5\x78\x78\xcd\x38\x30\x41\x29\xec\x4f\xbb\xc2\xe2\x9a\x30\x23\xa3\x09\xbf\x8e\xfc\xef\x75\x38\xf9\x3c\x2d\x7a\x64\xb9\x77\xc5\x7d\x59\x93\xfd\xe4\xd8\xda\x4b\x02\xcb\xb1\x8e\x0b\x0d\xd0\x32\x14\x5c\xa6\xb9\x68\xd3\xa5\xe5\xd7\x03\xed\xe2\x6b\xb4\xdd\x25\x70\x2a\xbc\x30\x27\xdf\xa6\x20\x61\x08\xa3\x6e\x4b\x06\x4b\x2e\x62\x3e\x30\x8a\xd3\x7d\xf3\xde\x1d\x63\x39\x56\x80\xe6\xc5\xb9\xb0\xf4\x42\xcf\xc8\x11\x8e\xa7\x16\x88\xa2\xb0\x54\xc3\xdf\x51\x48\x64\x81\xc5\x85\xcd\xae\xea\x19\x0e\xad\x21\xfa\xa4\x14\x09\xdb\xb5\x23\x38\x76\xfb\x79\x6b\x37\x42\x29\x7c\xf7\xc9\xa6\x16\x8e\xa6\x11\x9f\x35\x3f\xb5\x90\x7e\x6a\x26\x06\x25\xeb\xdc\x61\x5d\x06\xb7\x2e\x8c\x1a\xa9\x5a\x9a\x15\xde\x3b\x8d\x57\xdf\x50\xc9\xf3\xce\xea\x3e\x2a\x06\x57\xf2\xbf\xbb\x93\xa3\xff\xf0\x4e\x8e\xfe\xfe\x4e\x7e\xb9\xdb\x4e\x7e\x59\xbb\x93\x7f\x7f\xef\x46\xff\xf6\xde\xa9\x13\xda\x01\x4d\x7a\xfb\x48\xd2\x8d\x9e\x74\x04\x59\x97\x54\xaf\xd0\x8d\x65\x39\x33\x72\x99\xc2\x13\x48\x90\xdd\x5a\x18\x24\x25\xc7\x86\xd3\xbb\x52\xff\x44\xe8\xa7\xa1\xae\x7e\xaa\x7f\xe6\x25\xc5\x46\x16\x27\x59\x50\x38\x9d\xb6\x25\xce\x36\xe1\x15\x95\xc9\xb8\xc5\x2f\x6d\xd2\xf3\x2e\x06\x21\x0b\x78\xb0\xea\xa7\xb6\x89\xfe\x9d\x1d\x7e\x7d\x92\xdf\xc8\x75\x4e\x7d\xcb\xed\xad\x1e\x7d\xba\xcb\xb2\x21\xef\x59\xb2\x9c\x71\x77\x55\xa2\xbc\xdb\x94\x6b\x66\x82\xfa\x77\xb7\x6a\x9a\x45\xc5\x00\xbd\xef\xe4\x5d\xdc\x15\x47\xca\x8a\x61\xd6\xb1\xee\xbb\xe4\x2f\x9d\xba\xd0\x43\x67\xc0\x13\x42\xe4\x2d\xfe\xbf\x85\x67\x18\xba\xf2\x4a\xdb\x5b\xe5\x0f\xd7\xfb\xf2\xfe\x3d\x4f\xdd\x9a\x5f\xae\x30\x7e\xb9\xc2\xf8\xe5\x5e\x06\xc8\x14\x94\xfe\xb6\xe8\x98\xdd\xf0\xb7\x55\xb2\x87\x76\x6f\x5d\xf6\x6e\xbf\xbb\x7b\xab\xe8\x76\x6f\x3d\x9d\xa2\x73\x3c\x2f\xf6\x63\x77\xda\x7d\xbc\x6a\xfe\x78\x6c\xa8\x5f\x57\xbd\xe9\xfd\x54\x09\x3f\xda\xbb\xed\x6c\x7a\x97\x58\x9a\x95\x52\x12\x2b\x8b\x68\x16\x4e\xda\xde\xf8\xaf\x19\x39\x98\x16\xdc\xf0\xe7\x9a\xb0\xff\xbc\xc8\x81\xa8\xcd\x14\x4e\x0f\x83\x9a\x3e\x09\x8c\x8a\x2a\x11\xcc\xee\x14\x9d\xda\x51\x3b\xd1\x3e\xce\x7e\x5a\xa5\x53\xac\x19\x50\xcc\xb9\x5f\x16\x82\xf5\x3a\x36\x24\xe1\x5a\xdc\x4f\xe7\x57\x69\xbf\x41\xfc\x77\x30\x63\x22\x41\xbe\xa6\xe2\x36\x70\x0f\x16\x14\x7e\x4e\xbb\x53\x88\xb5\x44\x23\xd5\xa7\x33\xac\x12\x9f\x7c\x8a\xe1\xd8\x87\x19\x39\xd3\xdf\xde\xac\x13\x62\xa2\x92\x9a\xf2\xf7\xab\x18\x73\x6a\x4d\x5d\x6b\x22\x07\x0f\x2d\xf8\x32\x45\x2f\xa7\x4b\x39\x89\x5f\xa6\x18\x4c\xbb\x6a\xb1\x5e\xfd\xd2\x13\xf2\x76\x0a\xc6\xe9\x7f\x6c\xf5\x96\xec\x7a\x16\x6d\xf8\x1a\x7e\x99\xb6\x7b\xeb\xd4\x38\xb4\x72\x9b\x3e\x98\x8a\x66\x3d\x4d\xc4\x11\x02\x70\xb7\xaa\xdd\x2b\x1c\x87\xb3\x9a\xc3\x87\xd6\xf8\x7d\xc8\x6b\x3a\xb5\x11\xe2\x7e\x58\xa6\xb0\x5a\x26\x2d\x31\xb8\x59\xd9\x92\xe8\xb6\xed\x69\xdd\x64\x3d\x08\x39\x0f\x50\xb2\x6c\xf8\x18\x2e\x88\x39\x5f\x87\x05\xaf\xff\x43\x31\xb3\x6b\xd4\x77\xc6\xf0\x89\x88\xf5\xc8\xab\xb1\x2f\x1f\x85\x26\x90\xcf\x2b\x20\x85\x0f\x77\x3a\xb5\x0a\x61\xf5\xac\x8d\xb7\x85\x5c\xfa\x63\xda\xc8\x87\x81\x3c\x02\x46\xae\x72\xcb\xb1\x4e\xb1\x5c\x5d\xab\xb3\xc8\x24\x1e\x6c\xf6\x56\x0d\xc6\xa7\x8c\x1c\x4e\x57\xbe\x3c\x59\xe6\x24\x96\x9e\x35\x40\x81\x8f\x8a\x25\x9b\x4b\xc6\xa5\x55\x91\x89\x17\xb8\x6c\x4f\x17\xf0\xb2\x50\xe6\x7c\x9c\xde\xe2\x8b\xcf\x6c\x16\x14\x19\xa7\xfc\x5a\x8e\xe2\x36\x85\x80\x76\x49\xd1\x0c\x47\x1a\xe7\x13\x9d\xb7\xdd\x78\x43\xd7\xec\xd0\x3d\x6b\x43\xd6\x81\x77\x15\x8f\x88\x0a\xe7\xa0\x21\xee\x43\x40\x18\x66\xb7\x38\x67\xc6\x86\x91\xaf\x7a\x3a\xf4\x96\x60\xa8\xdc\xfa\x82\x47\x5a\x39\xd9\x77\x9d\xf9\x7f\xcf\x6c\x6b\x13\x2b\x70\x87\xce\x6d\xe5\xb7\x1f\x90\xdb\x57\x57\x43\xc1\xff\xc8\xe2\x16\x00\xb7\x6a\x9b\xb9\xed\x1c\xa7\x05\x34\x2e\x28\xbc\xba\x4d\x6d\x53\x93\x39\x6b\x07\x2e\x24\x1f\xa7\xb0\x13\x80\x11\x27\x41\x49\x2a\x83\xf8\x62\xb0\x8d\x1e\x74\x8f\x4c\xa6\x8a\x37\x3e\x5c\xf8\x14\x2e\x7c\xf2\x72\x4a\x21\xa1\x50\x3e\xb6\x6b\xaa\x0a\x54\x4f\x6e\x2d\x3d\x79\xb5\xf4\xa4\xac\x3d\xb9\x87\x1e\xc6\xad\xaf\xdb\x59\x7a\x48\xb4\x2c\x8a\xde\x28\xf3\xf0\xc8\x3c\xbc\xb2\x53\xea\xd8\xfe\x3f\xff\xb7\xb5\x12\xf8\xb1\xb4\x17\x4d\x34\x67\x70\x47\x4f\xdb\x5f\x07\x4b\x06\xee\x0b\x9f\xbc\x98\x76\x4b\x13\x3e\x8b\xb9\x62\x43\x97\x64\x89\xaf\xf4\x36\x3f\xfc\x54\xc0\x83\xff\x22\x69\xf2\x5b\xcd\xeb\x39\xf6\xe8\xd3\x07\x91\x2d\x79\x26\x49\xe2\x26\x74\x6c\x05\x4c\xb2\x81\xb5\x91\x38\x09\x3c\xf8\xaf\x7f\x66\x7f\x90\x2b\x36\x65\xda\x7d\xdc\xf9\xad\x1a\x1d\xc5\xd5\xfe\xf3\x81\xa2\x89\xe5\xa3\xc2\x15\xe8\xc5\x82\xa9\x7b\x3f\x29\xe4\xce\x04\xe8\xa1\x2e\x04\x9b\x4c\xbe\xf1\x20\xc2\x84\x00\x45\x76\x1a\x38\x9f\x76\x05\x4b\x16\x51\x92\xe2\x9f\xc9\xef\x7f\x8a\xdf\xff\x4c\x74\xb0\xe4\x3b\xad\xa9\x51\x2f\x67\x82\x33\x8b\x42\xd2\x5f\x5b\xee\x06\xeb\x6e\x6f\xc1\xe8\x21\x7c\x12\xe4\x7c\xaa\x8b\x27\xa2\xc5\x38\xff\xef\x41\x8e\x62\xfd\xf9\x4d\x6a\x16\x9e\xa9\x39\xc0\x79\x71\x80\x25\x1e\x60\x7e\x67\xec\x08\x07\x3e\x61\x6a\xa9\xff\x03\x68\xf2\xbf\x65\xde\x6d\x53\xfc\x4f\x23\xcc\xff\x81\x05\x2f\x49\xf4\xd2\xc7\xfc\x6d\xd4\x29\xfa\xad\x41\x16\x3a\x0f\x24\xb7\xd9\x36\x60\x99\xa6\x6f\xe0\xab\x3f\x7d\x48\x5d\x6e\x7b\xef\x21\x52\xbf\xde\x60\xf1\x26\xb6\x83\x39\x75\xfa\xe3\x03\x62\xed\xf3\x59\x91\xf4\x5c\xa1\xb3\xbd\x14\x6b\x4d\x51\xe7\x80\x58\x7b\x41\x24\xab\xb6\xb7\x9c\x98\xac\x5c\xf5\xec\x47\x1d\x16\xc4\x42\xe2\x9a\x93\x57\x53\xc8\x6d\xef\x00\x72\x9b\x9d\x41\x6e\x67\x58\x8c\x7e\x0a\x3e\xb0\x1a\x72\x2d\x73\x7d\xbc\x9d\x6a\x94\x7a\x59\xa2\xd4\xe9\x14\xab\x02\x9e\x52\xc8\x48\xd2\x07\x6b\xa7\x28\xea\x5b\x74\x9d\x94\x5d\x03\xdd\xf5\x78\x69\x69\x4b\xd2\x31\x27\x3f\xa7\xc0\x21\xd5\x19\x61\x3e\x68\x5d\xb2\x9a\xe3\x73\x5f\x47\x81\x2d\x28\xc8\xbe\x2b\x05\xf0\xbe\xcb\x05\xe4\xfd\x36\xe4\xf2\x2e\x21\x91\x40\xbd\x87\x09\xa4\x67\xfd\x3b\x7a\xc6\xfa\x9d\x1d\xbd\x27\x28\x57\x3e\x17\xbc\x37\x4f\xf3\x5e\x96\x9b\x8b\x19\x4b\x64\x4f\xa6\x3d\x5d\x93\x79\x89\x25\x1f\xab\x37\x6f\x39\xeb\xbd\x0f\x4f\x19\x79\xcd\xc9\x8c\xb0\xbe\x0e\x3f\xae\x7b\x60\xa7\x49\x18\x89\x89\xa6\x35\x5e\xea\xbc\xe6\xe4\x26\xa5\xe0\x6f\x3a\xd6\x9e\x7e\x5b\xb1\xef\x6a\xea\x69\xbf\x9b\x1a\xb4\x29\x2a\x8c\x07\x5b\xc6\xe3\xd0\xa8\x9f\x2a\x5f\x72\x73\xac\x36\xd0\xc3\xf8\x26\x30\xf9\xba\xb0\x5e\x4f\xe7\x5b\xd0\x67\x7d\x83\x58\xf7\x4d\x0a\x22\xd7\xda\x78\x1b\x99\x38\xb0\xb0\xaf\x2d\xda\x0f\x2d\x0a\xde\x9a\x79\xfe\x9f\x19\x68\xbc\x9a\x46\xc7\x64\x72\x5f\xa5\x27\x69\x1f\x99\x90\xcc\x02\x61\xb3\xb3\xa6\x2c\xaa\xdb\x91\x2b\xc2\x1e\xde\xc1\x8a\x5c\x6a\x86\x30\x05\xbe\xf5\x28\x98\x85\x07\x75\x26\x9e\x12\x74\xc3\x3b\x47\xdf\xbf\x67\x64\x39\x95\xb4\xac\x41\xd7\x27\xa3\x02\xa5\x14\x8e\x7c\x22\x68\x6b\xc2\xe5\xa5\xef\x5c\xaf\x18\x58\x27\xe6\x19\x44\xbe\x9c\x18\xe0\x35\x27\xdf\x7c\x92\x2c\x81\xbc\xfe\x70\x6b\x89\x88\xfc\x27\xc7\xdf\xe5\x31\xd7\x1a\x70\xb5\xaa\x62\x45\x2f\x5b\x29\x7a\x4e\x7c\xb5\x41\x57\x94\xc2\xbe\x4f\x92\x31\x1a\xc9\xfd\x3e\x08\xb8\x37\xa2\xd4\xd9\x93\xa5\x9e\x54\x2e\x28\x64\xfd\x96\xf4\x61\x66\x0d\x65\x43\x17\xc4\x6b\x09\xce\x30\x92\xdf\x64\x2f\xec\xf2\xd1\x62\x37\x0b\xed\xb4\xb8\xd6\x1b\xd1\x3b\x59\x18\x2f\x44\xb4\x65\x52\x8a\x21\xda\x79\x7f\x35\xec\xb5\xfa\xc4\x96\x81\x0e\xd4\x96\x2b\x20\xf3\xfa\x45\x9c\xb9\xba\x41\xd1\x33\x74\x81\x91\xb1\x26\x36\xb4\x80\xaa\xc2\x05\x65\x55\xed\x22\x3b\xd5\x2e\x71\xbf\x5e\x4b\x20\xe8\x77\x4b\x19\xe8\xfe\x24\x8b\x14\x88\xa7\x3e\xbc\xe6\x4d\x5d\x86\x28\xad\x05\xb5\xac\x71\x1f\x63\xf2\x99\x91\xf7\x3e\xaa\xc7\x96\x5c\xc4\x3d\x16\x5c\xf0\x1e\xfe\x3b\xb8\x8e\xe2\x38\x9d\x99\x1f\x66\xa6\x06\x0d\x20\x9e\x94\xe9\xf5\x52\x6c\x8f\xb6\x70\x27\x86\x05\x5f\x74\xbc\xee\x2b\x1a\x1b\x16\x14\xa6\xfd\x15\x15\x52\x14\x12\x9d\xa4\xbe\xa6\x3d\xef\xf0\x1c\x2b\x11\x97\x31\xac\x06\x0a\xf8\x86\x6a\xf1\x56\xb5\xd9\x77\x1a\xa2\x65\xbb\xe7\x7a\xd4\xc4\xf6\x2f\x41\xc1\x50\x69\x28\xe8\xff\x9f\x4c\x07\x0f\xd1\x07\x01\x2d\xbc\xb6\xe7\x2f\x3a\x29\xe2\xa4\x6f\x3c\x9d\x2e\x35\xf9\xf1\x2c\x0a\x17\xfd\xbb\xa8\x90\x6a\x7c\xa8\x48\x67\x6d\x41\xc3\x4a\x3a\xdc\x44\x19\x11\xfb\x2e\x45\xef\xcf\xc8\x65\xbf\x8d\x37\x5d\x32\xdd\x0d\x46\xc3\xdb\x63\x84\x44\x29\xeb\x5d\xb7\xf3\x93\xdd\xe1\xfb\x87\x65\x7e\x6e\x13\xbe\x7f\xa6\x99\x29\x7a\x0b\x53\x58\x05\x90\x41\x23\x66\xbf\xf4\x85\x3c\x52\x70\xfe\x3f\x4e\x2e\x0e\x39\x99\xf4\xff\xbb\x68\xc5\xca\xe0\xcb\x84\x42\x56\x9b\x78\xd1\x07\xeb\xcd\xae\x05\xc8\x3f\x23\x66\xd4\xf7\x34\x55\xef\x31\x89\x4d\x37\x01\x16\x2e\xa3\x65\xb3\x62\x0a\x96\x1a\xd9\x59\xd5\xa8\x55\x90\xc1\xf2\xc3\x9f\xaa\x76\xad\xab\x0c\x7a\xde\xdc\xbc\x97\x9d\x56\x6d\x05\xab\xad\x1b\x8e\xeb\x13\x92\x1c\x6f\x2b\xbc\x64\x76\xa6\x6c\x2d\x14\xcc\x16\x2c\x7b\xdd\x1c\xa7\xf0\xd9\x37\xe6\x12\x0a\x52\x97\xbe\x00\xa1\x88\x20\xd7\x44\xb0\xdf\x07\x09\xf7\x86\x25\x11\x5c\x50\x98\x19\xf6\x6e\xd3\xa2\x30\xd7\xd7\x7e\x1a\x60\x3e\x1b\xfd\xeb\x5a\xed\x13\xec\x99\x6e\xc6\x47\x05\xbe\xeb\xdf\x09\x9b\x5a\x14\x9e\xf7\xdd\x5f\xbb\x4e\x95\xe2\x1c\xbc\x89\x63\x74\xde\xd6\x02\x8e\x75\xab\xbe\x6b\x2d\xe0\xaa\xe8\x5d\x95\x3e\x51\x2d\xc7\xc5\xaf\x05\xec\x94\x3d\x4c\x49\x06\x6c\xd7\xd7\x0b\x78\xd3\xef\x4e\xae\xd4\x0a\xd8\x2b\x45\xce\x9f\xf7\x1b\x00\x7d\xdc\x2f\x48\xa0\x21\xf6\xc6\x23\x70\xd9\x11\xf0\xaa\xdf\xc8\x22\xbf\xd3\x6f\x02\xef\x71\x7f\xb1\xd0\x46\xa6\xb1\xd5\xab\xa2\x19\x17\x14\x0e\x6e\x65\x9d\x97\xa2\xf6\x37\x66\xe4\x8d\xc1\xa6\xab\xc1\xa7\xb5\x68\xf9\xf7\x8c\x08\x7b\x17\xb3\x92\x98\x68\x8a\x46\x6c\x85\xde\xe5\x6f\x48\xb5\x9f\xf7\xe1\xaa\x0f\x3b\x7d\x50\xab\x5b\x64\x0e\xbb\x16\xe9\x84\xcb\x4b\x9e\x67\x76\x94\x3e\x08\x52\x3f\xd3\xdb\x18\x25\x17\xfa\x62\xc2\x12\x76\xc1\xc5\x03\xbd\x0d\xaf\x79\x7c\x6d\x2d\xbe\x52\x38\x5a\x8f\x8d\x97\xdc\xb2\x8d\x54\xc0\x82\x00\x23\x9e\xac\x6d\x8c\x35\x2a\x02\x1b\x4c\xb6\x16\xb1\x6a\x80\x85\x2f\x3e\x49\x6c\xff\xb4\x89\x81\x8d\x4f\x53\xef\xba\x26\x20\xbc\xf5\x49\x2d\x9e\xf2\x73\xdf\x4d\x31\x83\xae\x12\x21\x4f\xfa\xdd\x95\x9b\x3f\xf8\x60\xe1\x5a\xa2\x6b\xbf\x92\x83\xe0\x73\x9f\x58\x99\x9c\xc7\x3c\xbb\xe4\x5c\x96\x8e\x53\x71\xca\x02\x74\x9a\x12\x24\xc7\x7c\xb1\xa5\x8f\x1d\x17\x22\x15\xa6\xe9\x9c\x13\xeb\x25\x8b\x62\x1e\x28\x8a\xaa\x9e\xe9\xed\x1c\x1f\xf7\x42\x91\x4e\x74\x3d\x12\x6a\x82\xdf\x74\x3a\xc4\xdd\x84\xfc\xf2\x9f\x3b\x67\x02\xfc\x7d\xe7\x0d\x03\xff\xc0\x69\xe5\x11\xfb\x63\x45\x11\xb6\x90\x6e\xb2\x85\xa3\x7e\x6c\x02\x73\xe6\xe4\x75\x0c\xd6\xff\xb2\x80\x24\xba\x10\x12\x7b\x08\xfa\xde\xd8\x52\xac\xc1\x21\x86\x83\x7d\x89\x15\x87\x90\xc1\x89\xc2\xf2\xb3\x71\x95\x34\xce\xa9\x32\xc9\x25\xb6\xe7\x29\x56\xd1\x66\x98\xab\x71\x01\xfe\xd0\x99\x4a\xf2\x52\x50\xf0\x1f\x3a\xcf\x63\xf0\x1f\x3b\x6d\xa9\x2b\x9f\x38\xbb\xe4\xaf\x17\x7a\xed\x91\x98\x3f\xaf\xc1\x8c\xb5\x58\x2c\xe8\x33\x91\xba\xbf\x3e\xb0\x28\x71\x7e\x45\x49\x24\x9d\x97\x82\x9c\x44\x94\x0c\xd5\x4b\x12\x7b\x2f\x9e\x8c\xcb\x42\xe8\xc6\x35\x2a\x4c\x05\x41\x76\xbb\x17\x25\x3d\x49\xf1\x8f\x18\x63\xb6\x1f\xcb\x75\xf9\xf8\x92\x3c\xa2\x4e\x42\xc4\x5f\xfc\x2b\xc8\xbf\xf8\x57\xea\xa8\x4b\x57\x5d\x2e\x08\x0e\x09\x22\xa5\x0e\x5e\xb9\x22\x5d\x10\xc5\xd1\xd0\x67\xff\x6f\x00\x00\x00\xff\xff\xc1\x46\x06\xd3\x92\xa7\x01\x00"), }, "/templates": &vfsgen۰DirInfo{ name: "templates", diff --git a/vendor/github.com/prometheus/alertmanager/config/config.go b/vendor/github.com/prometheus/alertmanager/config/config.go index e911e1b63c03..ea207858a89a 100644 --- a/vendor/github.com/prometheus/alertmanager/config/config.go +++ b/vendor/github.com/prometheus/alertmanager/config/config.go @@ -106,7 +106,7 @@ func (u URL) MarshalJSON() ([]byte, error) { if u.URL != nil { return json.Marshal(u.URL.String()) } - return nil, nil + return []byte("null"), nil } // UnmarshalJSON implements the json.Marshaler interface for URL. @@ -867,7 +867,7 @@ func (re Regexp) MarshalJSON() ([]byte, error) { if re.original != "" { return json.Marshal(re.original) } - return nil, nil + return []byte("null"), nil } // Matchers is label.Matchers with an added UnmarshalYAML method to implement the yaml.Unmarshaler interface @@ -920,7 +920,7 @@ func (m *Matchers) UnmarshalJSON(data []byte) error { // MarshalJSON implements the json.Marshaler interface for Matchers. func (m Matchers) MarshalJSON() ([]byte, error) { if len(m) == 0 { - return nil, nil + return []byte("[]"), nil } result := make([]string, len(m)) for i, matcher := range m { diff --git a/vendor/github.com/prometheus/alertmanager/dispatch/dispatch.go b/vendor/github.com/prometheus/alertmanager/dispatch/dispatch.go index b030046d6ddb..a31b869b5dea 100644 --- a/vendor/github.com/prometheus/alertmanager/dispatch/dispatch.go +++ b/vendor/github.com/prometheus/alertmanager/dispatch/dispatch.go @@ -33,12 +33,13 @@ import ( // DispatcherMetrics represents metrics associated to a dispatcher. type DispatcherMetrics struct { - aggrGroups prometheus.Gauge - processingDuration prometheus.Summary + aggrGroups prometheus.Gauge + processingDuration prometheus.Summary + aggrGroupLimitReached prometheus.Counter } // NewDispatcherMetrics returns a new registered DispatchMetrics. -func NewDispatcherMetrics(r prometheus.Registerer) *DispatcherMetrics { +func NewDispatcherMetrics(registerLimitMetrics bool, r prometheus.Registerer) *DispatcherMetrics { m := DispatcherMetrics{ aggrGroups: prometheus.NewGauge( prometheus.GaugeOpts{ @@ -52,10 +53,19 @@ func NewDispatcherMetrics(r prometheus.Registerer) *DispatcherMetrics { Help: "Summary of latencies for the processing of alerts.", }, ), + aggrGroupLimitReached: prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "alertmanager_dispatcher_aggregation_group_limit_reached_total", + Help: "Number of times when dispatcher failed to create new aggregation group due to limit.", + }, + ), } if r != nil { r.MustRegister(m.aggrGroups, m.processingDuration) + if registerLimitMetrics { + r.MustRegister(m.aggrGroupLimitReached) + } } return &m @@ -68,12 +78,14 @@ type Dispatcher struct { alerts provider.Alerts stage notify.Stage metrics *DispatcherMetrics + limits Limits marker types.Marker timeout func(time.Duration) time.Duration - aggrGroups map[*Route]map[model.Fingerprint]*aggrGroup - mtx sync.RWMutex + mtx sync.RWMutex + aggrGroupsPerRoute map[*Route]map[model.Fingerprint]*aggrGroup + aggrGroupsNum int done chan struct{} ctx context.Context @@ -82,6 +94,14 @@ type Dispatcher struct { logger log.Logger } +// Limits describes limits used by Dispatcher. +type Limits interface { + // MaxNumberOfAggregationGroups returns max number of aggregation groups that dispatcher can have. + // 0 or negative value = unlimited. + // If dispatcher hits this limit, it will not create additional groups, but will log an error instead. + MaxNumberOfAggregationGroups() int +} + // NewDispatcher returns a new Dispatcher. func NewDispatcher( ap provider.Alerts, @@ -89,9 +109,14 @@ func NewDispatcher( s notify.Stage, mk types.Marker, to func(time.Duration) time.Duration, + lim Limits, l log.Logger, m *DispatcherMetrics, ) *Dispatcher { + if lim == nil { + lim = nilLimits{} + } + disp := &Dispatcher{ alerts: ap, stage: s, @@ -100,6 +125,7 @@ func NewDispatcher( timeout: to, logger: log.With(l, "component", "dispatcher"), metrics: m, + limits: lim, } return disp } @@ -109,7 +135,8 @@ func (d *Dispatcher) Run() { d.done = make(chan struct{}) d.mtx.Lock() - d.aggrGroups = map[*Route]map[model.Fingerprint]*aggrGroup{} + d.aggrGroupsPerRoute = map[*Route]map[model.Fingerprint]*aggrGroup{} + d.aggrGroupsNum = 0 d.metrics.aggrGroups.Set(0) d.ctx, d.cancel = context.WithCancel(context.Background()) d.mtx.Unlock() @@ -152,11 +179,12 @@ func (d *Dispatcher) run(it provider.AlertIterator) { case <-cleanup.C: d.mtx.Lock() - for _, groups := range d.aggrGroups { + for _, groups := range d.aggrGroupsPerRoute { for _, ag := range groups { if ag.empty() { ag.stop() delete(groups, ag.fingerprint()) + d.aggrGroupsNum-- d.metrics.aggrGroups.Dec() } } @@ -201,7 +229,7 @@ func (d *Dispatcher) Groups(routeFilter func(*Route) bool, alertFilter func(*typ receivers := map[model.Fingerprint][]string{} now := time.Now() - for route, ags := range d.aggrGroups { + for route, ags := range d.aggrGroupsPerRoute { if !routeFilter(route) { continue } @@ -259,6 +287,7 @@ func (d *Dispatcher) Stop() { } d.mtx.Lock() if d.cancel == nil { + d.mtx.Unlock() return } d.cancel() @@ -283,36 +312,49 @@ func (d *Dispatcher) processAlert(alert *types.Alert, route *Route) { d.mtx.Lock() defer d.mtx.Unlock() - group, ok := d.aggrGroups[route] + routeGroups, ok := d.aggrGroupsPerRoute[route] if !ok { - group = map[model.Fingerprint]*aggrGroup{} - d.aggrGroups[route] = group + routeGroups = map[model.Fingerprint]*aggrGroup{} + d.aggrGroupsPerRoute[route] = routeGroups } - // If the group does not exist, create it. - ag, ok := group[fp] - if !ok { - ag = newAggrGroup(d.ctx, groupLabels, route, d.timeout, d.logger) - group[fp] = ag - d.metrics.aggrGroups.Inc() + ag, ok := routeGroups[fp] + if ok { + ag.insert(alert) + return + } - go ag.run(func(ctx context.Context, alerts ...*types.Alert) bool { - _, _, err := d.stage.Exec(ctx, d.logger, alerts...) - if err != nil { - lvl := level.Error(d.logger) - if ctx.Err() == context.Canceled { - // It is expected for the context to be canceled on - // configuration reload or shutdown. In this case, the - // message should only be logged at the debug level. - lvl = level.Debug(d.logger) - } - lvl.Log("msg", "Notify for alerts failed", "num_alerts", len(alerts), "err", err) - } - return err == nil - }) + // If the group does not exist, create it. But check the limit first. + if limit := d.limits.MaxNumberOfAggregationGroups(); limit > 0 && d.aggrGroupsNum >= limit { + d.metrics.aggrGroupLimitReached.Inc() + level.Error(d.logger).Log("msg", "Too many aggregation groups, cannot create new group for alert", "groups", d.aggrGroupsNum, "limit", limit, "alert", alert.Name()) + return } + ag = newAggrGroup(d.ctx, groupLabels, route, d.timeout, d.logger) + routeGroups[fp] = ag + d.aggrGroupsNum++ + d.metrics.aggrGroups.Inc() + + // Insert the 1st alert in the group before starting the group's run() + // function, to make sure that when the run() will be executed the 1st + // alert is already there. ag.insert(alert) + + go ag.run(func(ctx context.Context, alerts ...*types.Alert) bool { + _, _, err := d.stage.Exec(ctx, d.logger, alerts...) + if err != nil { + lvl := level.Error(d.logger) + if ctx.Err() == context.Canceled { + // It is expected for the context to be canceled on + // configuration reload or shutdown. In this case, the + // message should only be logged at the debug level. + lvl = level.Debug(d.logger) + } + lvl.Log("msg", "Notify for alerts failed", "num_alerts", len(alerts), "err", err) + } + return err == nil + }) } func getGroupLabels(alert *types.Alert, route *Route) model.LabelSet { @@ -492,3 +534,7 @@ func (ag *aggrGroup) flush(notify func(...*types.Alert) bool) { } } } + +type nilLimits struct{} + +func (n nilLimits) MaxNumberOfAggregationGroups() int { return 0 } diff --git a/vendor/github.com/prometheus/alertmanager/provider/mem/mem.go b/vendor/github.com/prometheus/alertmanager/provider/mem/mem.go index 575ad0d20b44..d45ce86d403d 100644 --- a/vendor/github.com/prometheus/alertmanager/provider/mem/mem.go +++ b/vendor/github.com/prometheus/alertmanager/provider/mem/mem.go @@ -38,16 +38,36 @@ type Alerts struct { listeners map[int]listeningAlerts next int + callback AlertStoreCallback + logger log.Logger } +type AlertStoreCallback interface { + // PreStore is called before alert is stored into the store. If this method returns error, + // alert is not stored. + // Existing flag indicates whether alert has existed before (and is only updated) or not. + // If alert has existed before, then alert passed to PreStore is result of merging existing alert with new alert. + PreStore(alert *types.Alert, existing bool) error + + // PostStore is called after alert has been put into store. + PostStore(alert *types.Alert, existing bool) + + // PostDelete is called after alert has been removed from the store due to alert garbage collection. + PostDelete(alert *types.Alert) +} + type listeningAlerts struct { alerts chan *types.Alert done chan struct{} } // NewAlerts returns a new alert provider. -func NewAlerts(ctx context.Context, m types.Marker, intervalGC time.Duration, l log.Logger) (*Alerts, error) { +func NewAlerts(ctx context.Context, m types.Marker, intervalGC time.Duration, alertCallback AlertStoreCallback, l log.Logger) (*Alerts, error) { + if alertCallback == nil { + alertCallback = noopCallback{} + } + ctx, cancel := context.WithCancel(ctx) a := &Alerts{ alerts: store.NewAlerts(), @@ -55,6 +75,7 @@ func NewAlerts(ctx context.Context, m types.Marker, intervalGC time.Duration, l listeners: map[int]listeningAlerts{}, next: 0, logger: log.With(l, "component", "provider"), + callback: alertCallback, } a.alerts.SetGCCallback(func(alerts []*types.Alert) { for _, alert := range alerts { @@ -62,6 +83,7 @@ func NewAlerts(ctx context.Context, m types.Marker, intervalGC time.Duration, l // they are resolved. Alerts waiting for resolved notifications are // held in memory in aggregation groups redundantly. m.Delete(alert.Fingerprint()) + a.callback.PostDelete(alert) } a.mtx.Lock() @@ -148,13 +170,16 @@ func (a *Alerts) Get(fp model.Fingerprint) (*types.Alert, error) { // Put adds the given alert to the set. func (a *Alerts) Put(alerts ...*types.Alert) error { - for _, alert := range alerts { fp := alert.Fingerprint() + existing := false + // Check that there's an alert existing within the store before // trying to merge. if old, err := a.alerts.Get(fp); err == nil { + existing = true + // Merge alerts if there is an overlap in activity range. if (alert.EndsAt.After(old.StartsAt) && alert.EndsAt.Before(old.EndsAt)) || (alert.StartsAt.After(old.StartsAt) && alert.StartsAt.Before(old.EndsAt)) { @@ -162,11 +187,18 @@ func (a *Alerts) Put(alerts ...*types.Alert) error { } } + if err := a.callback.PreStore(alert, existing); err != nil { + level.Error(a.logger).Log("msg", "pre-store callback returned error on set alert", "err", err) + continue + } + if err := a.alerts.Set(alert); err != nil { level.Error(a.logger).Log("msg", "error on set alert", "err", err) continue } + a.callback.PostStore(alert, existing) + a.mtx.Lock() for _, l := range a.listeners { select { @@ -179,3 +211,9 @@ func (a *Alerts) Put(alerts ...*types.Alert) error { return nil } + +type noopCallback struct{} + +func (n noopCallback) PreStore(_ *types.Alert, _ bool) error { return nil } +func (n noopCallback) PostStore(_ *types.Alert, _ bool) {} +func (n noopCallback) PostDelete(_ *types.Alert) {} diff --git a/vendor/github.com/prometheus/alertmanager/provider/provider.go b/vendor/github.com/prometheus/alertmanager/provider/provider.go index 1ab5fbe93fa3..91b5a741662c 100644 --- a/vendor/github.com/prometheus/alertmanager/provider/provider.go +++ b/vendor/github.com/prometheus/alertmanager/provider/provider.go @@ -83,6 +83,6 @@ type Alerts interface { GetPending() AlertIterator // Get returns the alert for a given fingerprint. Get(model.Fingerprint) (*types.Alert, error) - // Put adds the given alert to the set. + // Put adds the given set of alerts to the set. Put(...*types.Alert) error } diff --git a/vendor/github.com/prometheus/alertmanager/ui/Dockerfile b/vendor/github.com/prometheus/alertmanager/ui/Dockerfile index 4d15143d3e8d..8cdf0dd23001 100644 --- a/vendor/github.com/prometheus/alertmanager/ui/Dockerfile +++ b/vendor/github.com/prometheus/alertmanager/ui/Dockerfile @@ -7,6 +7,7 @@ ENV PATH=$PATH:/home/node/.npm-global/bin RUN mkdir -p $NPM_CONFIG_PREFIX; yarn global add \ elm@0.19.1 \ - elm-format@0.8.4 \ + elm-format@0.8.5 \ elm-test@0.19.1-revision6 \ - uglify-js@3.4.7 + uglify-js@3.13.4 \ + elm-review@2.5.0 diff --git a/vendor/github.com/prometheus/common/config/config.go b/vendor/github.com/prometheus/common/config/config.go index d8a7351f994f..fffda4a7ef45 100644 --- a/vendor/github.com/prometheus/common/config/config.go +++ b/vendor/github.com/prometheus/common/config/config.go @@ -16,7 +16,12 @@ package config -import "path/filepath" +import ( + "encoding/json" + "path/filepath" +) + +const secretToken = "" // Secret special type for storing secrets. type Secret string @@ -24,7 +29,7 @@ type Secret string // MarshalYAML implements the yaml.Marshaler interface for Secrets. func (s Secret) MarshalYAML() (interface{}, error) { if s != "" { - return "", nil + return secretToken, nil } return nil, nil } @@ -35,6 +40,14 @@ func (s *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error { return unmarshal((*plain)(s)) } +// MarshalJSON implements the json.Marshaler interface for Secret. +func (s Secret) MarshalJSON() ([]byte, error) { + if len(s) == 0 { + return json.Marshal("") + } + return json.Marshal(secretToken) +} + // DirectorySetter is a config type that contains file paths that may // be relative to the file containing the config. type DirectorySetter interface { diff --git a/vendor/github.com/prometheus/common/config/http_config.go b/vendor/github.com/prometheus/common/config/http_config.go index b98ff7cbd3c1..43f29672e004 100644 --- a/vendor/github.com/prometheus/common/config/http_config.go +++ b/vendor/github.com/prometheus/common/config/http_config.go @@ -21,6 +21,7 @@ import ( "crypto/sha256" "crypto/tls" "crypto/x509" + "encoding/json" "fmt" "io/ioutil" "net" @@ -54,9 +55,9 @@ type closeIdler interface { // BasicAuth contains basic HTTP authentication credentials. type BasicAuth struct { - Username string `yaml:"username"` - Password Secret `yaml:"password,omitempty"` - PasswordFile string `yaml:"password_file,omitempty"` + Username string `yaml:"username" json:"username"` + Password Secret `yaml:"password,omitempty" json:"password,omitempty"` + PasswordFile string `yaml:"password_file,omitempty" json:"password_file,omitempty"` } // SetDirectory joins any relative file paths with dir. @@ -69,9 +70,9 @@ func (a *BasicAuth) SetDirectory(dir string) { // Authorization contains HTTP authorization credentials. type Authorization struct { - Type string `yaml:"type,omitempty"` - Credentials Secret `yaml:"credentials,omitempty"` - CredentialsFile string `yaml:"credentials_file,omitempty"` + Type string `yaml:"type,omitempty" json:"type,omitempty"` + Credentials Secret `yaml:"credentials,omitempty" json:"credentials,omitempty"` + CredentialsFile string `yaml:"credentials_file,omitempty" json:"credentials_file,omitempty"` } // SetDirectory joins any relative file paths with dir. @@ -110,14 +111,36 @@ func (u URL) MarshalYAML() (interface{}, error) { return nil, nil } +// UnmarshalJSON implements the json.Marshaler interface for URL. +func (u *URL) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + urlp, err := url.Parse(s) + if err != nil { + return err + } + u.URL = urlp + return nil +} + +// MarshalJSON implements the json.Marshaler interface for URL. +func (u URL) MarshalJSON() ([]byte, error) { + if u.URL != nil { + return json.Marshal(u.URL.String()) + } + return []byte("null"), nil +} + // OAuth2 is the oauth2 client configuration. type OAuth2 struct { - ClientID string `yaml:"client_id"` - ClientSecret Secret `yaml:"client_secret"` - ClientSecretFile string `yaml:"client_secret_file"` - Scopes []string `yaml:"scopes,omitempty"` - TokenURL string `yaml:"token_url"` - EndpointParams map[string]string `yaml:"endpoint_params,omitempty"` + ClientID string `yaml:"client_id" json:"client_id"` + ClientSecret Secret `yaml:"client_secret" json:"client_secret"` + ClientSecretFile string `yaml:"client_secret_file" json:"client_secret_file"` + Scopes []string `yaml:"scopes,omitempty" json:"scopes,omitempty"` + TokenURL string `yaml:"token_url" json:"token_url"` + EndpointParams map[string]string `yaml:"endpoint_params,omitempty" json:"endpoint_params,omitempty"` } // SetDirectory joins any relative file paths with dir. @@ -131,25 +154,25 @@ func (a *OAuth2) SetDirectory(dir string) { // HTTPClientConfig configures an HTTP client. type HTTPClientConfig struct { // The HTTP basic authentication credentials for the targets. - BasicAuth *BasicAuth `yaml:"basic_auth,omitempty"` + BasicAuth *BasicAuth `yaml:"basic_auth,omitempty" json:"basic_auth,omitempty"` // The HTTP authorization credentials for the targets. - Authorization *Authorization `yaml:"authorization,omitempty"` + Authorization *Authorization `yaml:"authorization,omitempty" json:"authorization,omitempty"` // The OAuth2 client credentials used to fetch a token for the targets. - OAuth2 *OAuth2 `yaml:"oauth2,omitempty"` + OAuth2 *OAuth2 `yaml:"oauth2,omitempty" json:"oauth2,omitempty"` // The bearer token for the targets. Deprecated in favour of // Authorization.Credentials. - BearerToken Secret `yaml:"bearer_token,omitempty"` + BearerToken Secret `yaml:"bearer_token,omitempty" json:"bearer_token,omitempty"` // The bearer token file for the targets. Deprecated in favour of // Authorization.CredentialsFile. - BearerTokenFile string `yaml:"bearer_token_file,omitempty"` + BearerTokenFile string `yaml:"bearer_token_file,omitempty" json:"bearer_token_file,omitempty"` // HTTP proxy server to use to connect to the targets. - ProxyURL URL `yaml:"proxy_url,omitempty"` + ProxyURL URL `yaml:"proxy_url,omitempty" json:"proxy_url,omitempty"` // TLSConfig to use to connect to the targets. - TLSConfig TLSConfig `yaml:"tls_config,omitempty"` + TLSConfig TLSConfig `yaml:"tls_config,omitempty" json:"tls_config,omitempty"` // FollowRedirects specifies whether the client should follow HTTP 3xx redirects. // The omitempty flag is not set, because it would be hidden from the // marshalled configuration when set to false. - FollowRedirects bool `yaml:"follow_redirects"` + FollowRedirects bool `yaml:"follow_redirects" json:"follow_redirects"` } // SetDirectory joins any relative file paths with dir. @@ -236,6 +259,16 @@ func (c *HTTPClientConfig) UnmarshalYAML(unmarshal func(interface{}) error) erro return c.Validate() } +// UnmarshalJSON implements the json.Marshaler interface for URL. +func (c *HTTPClientConfig) UnmarshalJSON(data []byte) error { + type plain HTTPClientConfig + *c = DefaultHTTPClientConfig + if err := json.Unmarshal(data, (*plain)(c)); err != nil { + return err + } + return c.Validate() +} + // UnmarshalYAML implements the yaml.Unmarshaler interface. func (a *BasicAuth) UnmarshalYAML(unmarshal func(interface{}) error) error { type plain BasicAuth @@ -387,7 +420,7 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT return newRT(tlsConfig) } - return newTLSRoundTripper(tlsConfig, cfg.TLSConfig.CAFile, newRT) + return NewTLSRoundTripper(tlsConfig, cfg.TLSConfig.CAFile, newRT) } type authorizationCredentialsRoundTripper struct { @@ -616,15 +649,15 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) { // TLSConfig configures the options for TLS connections. type TLSConfig struct { // The CA cert to use for the targets. - CAFile string `yaml:"ca_file,omitempty"` + CAFile string `yaml:"ca_file,omitempty" json:"ca_file,omitempty"` // The client cert file for the targets. - CertFile string `yaml:"cert_file,omitempty"` + CertFile string `yaml:"cert_file,omitempty" json:"cert_file,omitempty"` // The client key file for the targets. - KeyFile string `yaml:"key_file,omitempty"` + KeyFile string `yaml:"key_file,omitempty" json:"key_file,omitempty"` // Used to verify the hostname for the targets. - ServerName string `yaml:"server_name,omitempty"` + ServerName string `yaml:"server_name,omitempty" json:"server_name,omitempty"` // Disable target certificate validation. - InsecureSkipVerify bool `yaml:"insecure_skip_verify"` + InsecureSkipVerify bool `yaml:"insecure_skip_verify" json:"insecure_skip_verify"` } // SetDirectory joins any relative file paths with dir. @@ -684,7 +717,7 @@ type tlsRoundTripper struct { tlsConfig *tls.Config } -func newTLSRoundTripper( +func NewTLSRoundTripper( cfg *tls.Config, caFile string, newRT func(*tls.Config) (http.RoundTripper, error), diff --git a/vendor/github.com/prometheus/common/model/labels.go b/vendor/github.com/prometheus/common/model/labels.go index 41051a01a36d..ef8956335468 100644 --- a/vendor/github.com/prometheus/common/model/labels.go +++ b/vendor/github.com/prometheus/common/model/labels.go @@ -45,6 +45,14 @@ const ( // scrape a target. MetricsPathLabel = "__metrics_path__" + // ScrapeIntervalLabel is the name of the label that holds the scrape interval + // used to scrape a target. + ScrapeIntervalLabel = "__scrape_interval__" + + // ScrapeTimeoutLabel is the name of the label that holds the scrape + // timeout used to scrape a target. + ScrapeTimeoutLabel = "__scrape_timeout__" + // ReservedLabelPrefix is a prefix which is not legal in user-supplied // label names. ReservedLabelPrefix = "__" diff --git a/vendor/go.opentelemetry.io/otel/.gitignore b/vendor/go.opentelemetry.io/otel/.gitignore index cbef19714a7c..69f09e575fce 100644 --- a/vendor/go.opentelemetry.io/otel/.gitignore +++ b/vendor/go.opentelemetry.io/otel/.gitignore @@ -10,13 +10,10 @@ coverage.* gen/ -/example/basic/basic -/example/grpc/client/client -/example/grpc/server/server -/example/http/client/client -/example/http/server/server /example/jaeger/jaeger /example/namedtracer/namedtracer +/example/opencensus/opencensus /example/prometheus/prometheus +/example/prom-collector/prom-collector /example/zipkin/zipkin /example/otel-collector/otel-collector diff --git a/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/vendor/go.opentelemetry.io/otel/CHANGELOG.md index e553b56ae9c6..2702ccda2550 100644 --- a/vendor/go.opentelemetry.io/otel/CHANGELOG.md +++ b/vendor/go.opentelemetry.io/otel/CHANGELOG.md @@ -8,15 +8,515 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Added + +### Changed + +### Deprecated + +### Removed + +### Fixed + +### Security + +## [0.20.0] - 2021-04-23 + +### Added + +- The OTLP exporter now has two new convenience functions, `NewExportPipeline` and `InstallNewPipeline`, setup and install the exporter in tracing and metrics pipelines. (#1373) +- Adds semantic conventions for exceptions. (#1492) +- Added Jaeger Environment variables: `OTEL_EXPORTER_JAEGER_AGENT_HOST`, `OTEL_EXPORTER_JAEGER_AGENT_PORT` + These environment variables can be used to override Jaeger agent hostname and port (#1752) +- Option `ExportTimeout` was added to batch span processor. (#1755) +- `trace.TraceFlags` is now a defined type over `byte` and `WithSampled(bool) TraceFlags` and `IsSampled() bool` methods have been added to it. (#1770) +- The `Event` and `Link` struct types from the `go.opentelemetry.io/otel` package now include a `DroppedAttributeCount` field to record the number of attributes that were not recorded due to configured limits being reached. (#1771) +- The Jaeger exporter now reports dropped attributes for a Span event in the exported log. (#1771) +- Adds test to check BatchSpanProcessor ignores `OnEnd` and `ForceFlush` post `Shutdown`. (#1772) +- Extract resource attributes from the `OTEL_RESOURCE_ATTRIBUTES` environment variable and merge them with the `resource.Default` resource as well as resources provided to the `TracerProvider` and metric `Controller`. (#1785) +- Added `WithOSType` resource configuration option to set OS (Operating System) type resource attribute (`os.type`). (#1788) +- Added `WithProcess*` resource configuration options to set Process resource attributes. (#1788) + - `process.pid` + - `process.executable.name` + - `process.executable.path` + - `process.command_args` + - `process.owner` + - `process.runtime.name` + - `process.runtime.version` + - `process.runtime.description` +- Adds `k8s.node.name` and `k8s.node.uid` attribute keys to the `semconv` package. (#1789) +- Added support for configuring OTLP/HTTP and OTLP/gRPC Endpoints, TLS Certificates, Headers, Compression and Timeout via Environment Variables. (#1758, #1769 and #1811) + - `OTEL_EXPORTER_OTLP_ENDPOINT` + - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` + - `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` + - `OTEL_EXPORTER_OTLP_HEADERS` + - `OTEL_EXPORTER_OTLP_TRACES_HEADERS` + - `OTEL_EXPORTER_OTLP_METRICS_HEADERS` + - `OTEL_EXPORTER_OTLP_COMPRESSION` + - `OTEL_EXPORTER_OTLP_TRACES_COMPRESSION` + - `OTEL_EXPORTER_OTLP_METRICS_COMPRESSION` + - `OTEL_EXPORTER_OTLP_TIMEOUT` + - `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` + - `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT` + - `OTEL_EXPORTER_OTLP_CERTIFICATE` + - `OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE` + - `OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE` +- Adds `otlpgrpc.WithTimeout` option for configuring timeout to the otlp/gRPC exporter. (#1821) + +### Fixed + +- The `Span.IsRecording` implementation from `go.opentelemetry.io/otel/sdk/trace` always returns false when not being sampled. (#1750) +- The Jaeger exporter now correctly sets tags for the Span status code and message. + This means it uses the correct tag keys (`"otel.status_code"`, `"otel.status_description"`) and does not set the status message as a tag unless it is set on the span. (#1761) +- The Jaeger exporter now correctly records Span event's names using the `"event"` key for a tag. + Additionally, this tag is overridden, as specified in the OTel specification, if the event contains an attribute with that key. (#1768) +- Zipkin Exporter: Ensure mapping between OTel and Zipkin span data complies with the specification. (#1688) +- Fixed typo for default service name in Jaeger Exporter. (#1797) +- Fix flaky OTLP for the reconnnection of the client connection. (#1527, #1814) + +### Changed + +- Span `RecordError` now records an `exception` event to comply with the semantic convention specification. (#1492) +- Jaeger exporter was updated to use thrift v0.14.1. (#1712) +- Migrate from using internally built and maintained version of the OTLP to the one hosted at `go.opentelemetry.io/proto/otlp`. (#1713) +- Migrate from using `github.com/gogo/protobuf` to `google.golang.org/protobuf` to match `go.opentelemetry.io/proto/otlp`. (#1713) +- The storage of a local or remote Span in a `context.Context` using its SpanContext is unified to store just the current Span. + The Span's SpanContext can now self-identify as being remote or not. + This means that `"go.opentelemetry.io/otel/trace".ContextWithRemoteSpanContext` will now overwrite any existing current Span, not just existing remote Spans, and make it the current Span in a `context.Context`. (#1731) +- Improve OTLP/gRPC exporter connection errors. (#1737) +- Information about a parent span context in a `"go.opentelemetry.io/otel/export/trace".SpanSnapshot` is unified in a new `Parent` field. + The existing `ParentSpanID` and `HasRemoteParent` fields are removed in favor of this. (#1748) +- The `ParentContext` field of the `"go.opentelemetry.io/otel/sdk/trace".SamplingParameters` is updated to hold a `context.Context` containing the parent span. + This changes it to make `SamplingParameters` conform with the OpenTelemetry specification. (#1749) +- Updated Jaeger Environment Variables: `JAEGER_ENDPOINT`, `JAEGER_USER`, `JAEGER_PASSWORD` + to `OTEL_EXPORTER_JAEGER_ENDPOINT`, `OTEL_EXPORTER_JAEGER_USER`, `OTEL_EXPORTER_JAEGER_PASSWORD` + in compliance with OTel spec (#1752) +- Modify `BatchSpanProcessor.ForceFlush` to abort after timeout/cancellation. (#1757) +- The `DroppedAttributeCount` field of the `Span` in the `go.opentelemetry.io/otel` package now only represents the number of attributes dropped for the span itself. + It no longer is a conglomerate of itself, events, and link attributes that have been dropped. (#1771) +- Make `ExportSpans` in Jaeger Exporter honor context deadline. (#1773) +- Modify Zipkin Exporter default service name, use default resouce's serviceName instead of empty. (#1777) +- The `go.opentelemetry.io/otel/sdk/export/trace` package is merged into the `go.opentelemetry.io/otel/sdk/trace` package. (#1778) +- The prometheus.InstallNewPipeline example is moved from comment to example test (#1796) +- The convenience functions for the stdout exporter have been updated to return the `TracerProvider` implementation and enable the shutdown of the exporter. (#1800) +- Replace the flush function returned from the Jaeger exporter's convenience creation functions (`InstallNewPipeline` and `NewExportPipeline`) with the `TracerProvider` implementation they create. + This enables the caller to shutdown and flush using the related `TracerProvider` methods. (#1822) +- Updated the Jaeger exporter to have a default enpoint, `http://localhost:14250`, for the collector. (#1824) +- Changed the function `WithCollectorEndpoint` in the Jaeger exporter to no longer accept an endpoint as an argument. + The endpoint can be passed with the `CollectorEndpointOption` using the `WithEndpoint` function or by setting the `OTEL_EXPORTER_JAEGER_ENDPOINT` environment variable value appropriately. (#1824) +- The Jaeger exporter no longer batches exported spans itself, instead it relies on the SDK's `BatchSpanProcessor` for this functionality. (#1830) +- The Jaeger exporter creation functions (`NewRawExporter`, `NewExportPipeline`, and `InstallNewPipeline`) no longer accept the removed `Option` type as a variadic argument. (#1830) + +### Removed + +- Removed Jaeger Environment variables: `JAEGER_SERVICE_NAME`, `JAEGER_DISABLED`, `JAEGER_TAGS` + These environment variables will no longer be used to override values of the Jaeger exporter (#1752) +- No longer set the links for a `Span` in `go.opentelemetry.io/otel/sdk/trace` that is configured to be a new root. + This is unspecified behavior that the OpenTelemetry community plans to standardize in the future. + To prevent backwards incompatible changes when it is specified, these links are removed. (#1726) +- Setting error status while recording error with Span from oteltest package. (#1729) +- The concept of a remote and local Span stored in a context is unified to just the current Span. + Because of this `"go.opentelemetry.io/otel/trace".RemoteSpanContextFromContext` is removed as it is no longer needed. + Instead, `"go.opentelemetry.io/otel/trace".SpanContextFromContex` can be used to return the current Span. + If needed, that Span's `SpanContext.IsRemote()` can then be used to determine if it is remote or not. (#1731) +- The `HasRemoteParent` field of the `"go.opentelemetry.io/otel/sdk/trace".SamplingParameters` is removed. + This field is redundant to the information returned from the `Remote` method of the `SpanContext` held in the `ParentContext` field. (#1749) +- The `trace.FlagsDebug` and `trace.FlagsDeferred` constants have been removed and will be localized to the B3 propagator. (#1770) +- Remove `Process` configuration, `WithProcessFromEnv` and `ProcessFromEnv`, and type from the Jaeger exporter package. + The information that could be configured in the `Process` struct should be configured in a `Resource` instead. (#1776, #1804) +- Remove the `WithDisabled` option from the Jaeger exporter. + To disable the exporter unregister it from the `TracerProvider` or use a no-operation `TracerProvider`. (#1806) +- Removed the functions `CollectorEndpointFromEnv` and `WithCollectorEndpointOptionFromEnv` from the Jaeger exporter. + These functions for retrieving specific environment variable values are redundant of other internal functions and + are not intended for end user use. (#1824) +- Removed the Jaeger exporter `WithSDKOptions` `Option`. + This option was used to set SDK options for the exporter creation convenience functions. + These functions are provided as a way to easily setup or install the exporter with what are deemed reasonable SDK settings for common use cases. + If the SDK needs to be configured differently, the `NewRawExporter` function and direct setup of the SDK with the desired settings should be used. (#1825) +- The `WithBufferMaxCount` and `WithBatchMaxCount` `Option`s from the Jaeger exporter are removed. + The exporter no longer batches exports, instead relying on the SDK's `BatchSpanProcessor` for this functionality. (#1830) +- The Jaeger exporter `Option` type is removed. + The type is no longer used by the exporter to configure anything. + All of the previous configuration these options provided were duplicates of SDK configuration. + They have all been removed in favor of using the SDK configuration and focuses the exporter configuration to be only about the endpoints it will send telemetry to. (#1830) + +## [0.19.0] - 2021-03-18 + +### Added + +- Added `Marshaler` config option to `otlphttp` to enable otlp over json or protobufs. (#1586) +- A `ForceFlush` method to the `"go.opentelemetry.io/otel/sdk/trace".TracerProvider` to flush all registered `SpanProcessor`s. (#1608) +- Added `WithSampler` and `WithSpanLimits` to tracer provider. (#1633, #1702) +- `"go.opentelemetry.io/otel/trace".SpanContext` now has a `remote` property, and `IsRemote()` predicate, that is true when the `SpanContext` has been extracted from remote context data. (#1701) +- A `Valid` method to the `"go.opentelemetry.io/otel/attribute".KeyValue` type. (#1703) + +### Changed + +- `trace.SpanContext` is now immutable and has no exported fields. (#1573) + - `trace.NewSpanContext()` can be used in conjunction with the `trace.SpanContextConfig` struct to initialize a new `SpanContext` where all values are known. +- Update the `ForceFlush` method signature to the `"go.opentelemetry.io/otel/sdk/trace".SpanProcessor` to accept a `context.Context` and return an error. (#1608) +- Update the `Shutdown` method to the `"go.opentelemetry.io/otel/sdk/trace".TracerProvider` return an error on shutdown failure. (#1608) +- The SimpleSpanProcessor will now shut down the enclosed `SpanExporter` and gracefully ignore subsequent calls to `OnEnd` after `Shutdown` is called. (#1612) +- `"go.opentelemetry.io/sdk/metric/controller.basic".WithPusher` is replaced with `WithExporter` to provide consistent naming across project. (#1656) +- Added non-empty string check for trace `Attribute` keys. (#1659) +- Add `description` to SpanStatus only when `StatusCode` is set to error. (#1662) +- Jaeger exporter falls back to `resource.Default`'s `service.name` if the exported Span does not have one. (#1673) +- Jaeger exporter populates Jaeger's Span Process from Resource. (#1673) +- Renamed the `LabelSet` method of `"go.opentelemetry.io/otel/sdk/resource".Resource` to `Set`. (#1692) +- Changed `WithSDK` to `WithSDKOptions` to accept variadic arguments of `TracerProviderOption` type in `go.opentelemetry.io/otel/exporters/trace/jaeger` package. (#1693) +- Changed `WithSDK` to `WithSDKOptions` to accept variadic arguments of `TracerProviderOption` type in `go.opentelemetry.io/otel/exporters/trace/zipkin` package. (#1693) + +### Removed + +- Removed `serviceName` parameter from Zipkin exporter and uses resource instead. (#1549) +- Removed `WithConfig` from tracer provider to avoid overriding configuration. (#1633) +- Removed the exported `SimpleSpanProcessor` and `BatchSpanProcessor` structs. + These are now returned as a SpanProcessor interface from their respective constructors. (#1638) +- Removed `WithRecord()` from `trace.SpanOption` when creating a span. (#1660) +- Removed setting status to `Error` while recording an error as a span event in `RecordError`. (#1663) +- Removed `jaeger.WithProcess` configuration option. (#1673) +- Removed `ApplyConfig` method from `"go.opentelemetry.io/otel/sdk/trace".TracerProvider` and the now unneeded `Config` struct. (#1693) + +### Fixed + +- Jaeger Exporter: Ensure mapping between OTEL and Jaeger span data complies with the specification. (#1626) +- `SamplingResult.TraceState` is correctly propagated to a newly created span's `SpanContext`. (#1655) +- The `otel-collector` example now correctly flushes metric events prior to shutting down the exporter. (#1678) +- Do not set span status message in `SpanStatusFromHTTPStatusCode` if it can be inferred from `http.status_code`. (#1681) +- Synchronization issues in global trace delegate implementation. (#1686) +- Reduced excess memory usage by global `TracerProvider`. (#1687) + +## [0.18.0] - 2021-03-03 + +### Added + +- Added `resource.Default()` for use with meter and tracer providers. (#1507) +- `AttributePerEventCountLimit` and `AttributePerLinkCountLimit` for `SpanLimits`. (#1535) +- Added `Keys()` method to `propagation.TextMapCarrier` and `propagation.HeaderCarrier` to adapt `http.Header` to this interface. (#1544) +- Added `code` attributes to `go.opentelemetry.io/otel/semconv` package. (#1558) +- Compatibility testing suite in the CI system for the following systems. (#1567) + | OS | Go Version | Architecture | + | ------- | ---------- | ------------ | + | Ubuntu | 1.15 | amd64 | + | Ubuntu | 1.14 | amd64 | + | Ubuntu | 1.15 | 386 | + | Ubuntu | 1.14 | 386 | + | MacOS | 1.15 | amd64 | + | MacOS | 1.14 | amd64 | + | Windows | 1.15 | amd64 | + | Windows | 1.14 | amd64 | + | Windows | 1.15 | 386 | + | Windows | 1.14 | 386 | + +### Changed + +- Replaced interface `oteltest.SpanRecorder` with its existing implementation + `StandardSpanRecorder`. (#1542) +- Default span limit values to 128. (#1535) +- Rename `MaxEventsPerSpan`, `MaxAttributesPerSpan` and `MaxLinksPerSpan` to `EventCountLimit`, `AttributeCountLimit` and `LinkCountLimit`, and move these fields into `SpanLimits`. (#1535) +- Renamed the `otel/label` package to `otel/attribute`. (#1541) +- Vendor the Jaeger exporter's dependency on Apache Thrift. (#1551) +- Parallelize the CI linting and testing. (#1567) +- Stagger timestamps in exact aggregator tests. (#1569) +- Changed all examples to use `WithBatchTimeout(5 * time.Second)` rather than `WithBatchTimeout(5)`. (#1621) +- Prevent end-users from implementing some interfaces (#1575) +``` + "otel/exporters/otlp/otlphttp".Option + "otel/exporters/stdout".Option + "otel/oteltest".Option + "otel/trace".TracerOption + "otel/trace".SpanOption + "otel/trace".EventOption + "otel/trace".LifeCycleOption + "otel/trace".InstrumentationOption + "otel/sdk/resource".Option + "otel/sdk/trace".ParentBasedSamplerOption + "otel/sdk/trace".ReadOnlySpan + "otel/sdk/trace".ReadWriteSpan +``` +### Removed + +- Removed attempt to resample spans upon changing the span name with `span.SetName()`. (#1545) +- The `test-benchmark` is no longer a dependency of the `precommit` make target. (#1567) +- Removed the `test-386` make target. + This was replaced with a full compatibility testing suite (i.e. multi OS/arch) in the CI system. (#1567) + +### Fixed + +- The sequential timing check of timestamps in the stdout exporter are now setup explicitly to be sequential (#1571). (#1572) +- Windows build of Jaeger tests now compiles with OS specific functions (#1576). (#1577) +- The sequential timing check of timestamps of go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue are now setup explicitly to be sequential (#1578). (#1579) +- Validate tracestate header keys with vendors according to the W3C TraceContext specification (#1475). (#1581) +- The OTLP exporter includes related labels for translations of a GaugeArray (#1563). (#1570) + +## [0.17.0] - 2021-02-12 + +### Changed + +- Rename project default branch from `master` to `main`. (#1505) +- Reverse order in which `Resource` attributes are merged, per change in spec. (#1501) +- Add tooling to maintain "replace" directives in go.mod files automatically. (#1528) +- Create new modules: otel/metric, otel/trace, otel/oteltest, otel/sdk/export/metric, otel/sdk/metric (#1528) +- Move metric-related public global APIs from otel to otel/metric/global. (#1528) + +## Fixed + +- Fixed otlpgrpc reconnection issue. +- The example code in the README.md of `go.opentelemetry.io/otel/exporters/otlp` is moved to a compiled example test and used the new `WithAddress` instead of `WithEndpoint`. (#1513) +- The otel-collector example now uses the default OTLP receiver port of the collector. + +## [0.16.0] - 2021-01-13 + +### Added + +- Add the `ReadOnlySpan` and `ReadWriteSpan` interfaces to provide better control for accessing span data. (#1360) +- `NewGRPCDriver` function returns a `ProtocolDriver` that maintains a single gRPC connection to the collector. (#1369) +- Added documentation about the project's versioning policy. (#1388) +- Added `NewSplitDriver` for OTLP exporter that allows sending traces and metrics to different endpoints. (#1418) +- Added codeql worfklow to GitHub Actions (#1428) +- Added Gosec workflow to GitHub Actions (#1429) +- Add new HTTP driver for OTLP exporter in `exporters/otlp/otlphttp`. Currently it only supports the binary protobuf payloads. (#1420) +- Add an OpenCensus exporter bridge. (#1444) + +### Changed + +- Rename `internal/testing` to `internal/internaltest`. (#1449) +- Rename `export.SpanData` to `export.SpanSnapshot` and use it only for exporting spans. (#1360) +- Store the parent's full `SpanContext` rather than just its span ID in the `span` struct. (#1360) +- Improve span duration accuracy. (#1360) +- Migrated CI/CD from CircleCI to GitHub Actions (#1382) +- Remove duplicate checkout from GitHub Actions workflow (#1407) +- Metric `array` aggregator renamed `exact` to match its `aggregation.Kind` (#1412) +- Metric `exact` aggregator includes per-point timestamps (#1412) +- Metric stdout exporter uses MinMaxSumCount aggregator for ValueRecorder instruments (#1412) +- `NewExporter` from `exporters/otlp` now takes a `ProtocolDriver` as a parameter. (#1369) +- Many OTLP Exporter options became gRPC ProtocolDriver options. (#1369) +- Unify endpoint API that related to OTel exporter. (#1401) +- Optimize metric histogram aggregator to re-use its slice of buckets. (#1435) +- Metric aggregator Count() and histogram Bucket.Counts are consistently `uint64`. (1430) +- Histogram aggregator accepts functional options, uses default boundaries if none given. (#1434) +- `SamplingResult` now passed a `Tracestate` from the parent `SpanContext` (#1432) +- Moved gRPC driver for OTLP exporter to `exporters/otlp/otlpgrpc`. (#1420) +- The `TraceContext` propagator now correctly propagates `TraceState` through the `SpanContext`. (#1447) +- Metric Push and Pull Controller components are combined into a single "basic" Controller: + - `WithExporter()` and `Start()` to configure Push behavior + - `Start()` is optional; use `Collect()` and `ForEach()` for Pull behavior + - `Start()` and `Stop()` accept Context. (#1378) +- The `Event` type is moved from the `otel/sdk/export/trace` package to the `otel/trace` API package. (#1452) + +### Removed + +- Remove `errUninitializedSpan` as its only usage is now obsolete. (#1360) +- Remove Metric export functionality related to quantiles and summary data points: this is not specified (#1412) +- Remove DDSketch metric aggregator; our intention is to re-introduce this as an option of the histogram aggregator after [new OTLP histogram data types](https://github.com/open-telemetry/opentelemetry-proto/pull/226) are released (#1412) + +### Fixed + +- `BatchSpanProcessor.Shutdown()` will now shutdown underlying `export.SpanExporter`. (#1443) + +## [0.15.0] - 2020-12-10 + +### Added + +- The `WithIDGenerator` `TracerProviderOption` is added to the `go.opentelemetry.io/otel/trace` package to configure an `IDGenerator` for the `TracerProvider`. (#1363) + +### Changed + +- The Zipkin exporter now uses the Span status code to determine. (#1328) +- `NewExporter` and `Start` functions in `go.opentelemetry.io/otel/exporters/otlp` now receive `context.Context` as a first parameter. (#1357) +- Move the OpenCensus example into `example` directory. (#1359) +- Moved the SDK's `internal.IDGenerator` interface in to the `sdk/trace` package to enable support for externally-defined ID generators. (#1363) +- Bump `github.com/google/go-cmp` from 0.5.3 to 0.5.4 (#1374) +- Bump `github.com/golangci/golangci-lint` in `/internal/tools` (#1375) + +### Fixed + +- Metric SDK `SumObserver` and `UpDownSumObserver` instruments correctness fixes. (#1381) + +## [0.14.0] - 2020-11-19 + +### Added + +- An `EventOption` and the related `NewEventConfig` function are added to the `go.opentelemetry.io/otel` package to configure Span events. (#1254) +- A `TextMapPropagator` and associated `TextMapCarrier` are added to the `go.opentelemetry.io/otel/oteltest` package to test `TextMap` type propagators and their use. (#1259) +- `SpanContextFromContext` returns `SpanContext` from context. (#1255) +- `TraceState` has been added to `SpanContext`. (#1340) +- `DeploymentEnvironmentKey` added to `go.opentelemetry.io/otel/semconv` package. (#1323) +- Add an OpenCensus to OpenTelemetry tracing bridge. (#1305) +- Add a parent context argument to `SpanProcessor.OnStart` to follow the specification. (#1333) +- Add missing tests for `sdk/trace/attributes_map.go`. (#1337) + +### Changed + +- Move the `go.opentelemetry.io/otel/api/trace` package into `go.opentelemetry.io/otel/trace` with the following changes. (#1229) (#1307) + - `ID` has been renamed to `TraceID`. + - `IDFromHex` has been renamed to `TraceIDFromHex`. + - `EmptySpanContext` is removed. +- Move the `go.opentelemetry.io/otel/api/trace/tracetest` package into `go.opentelemetry.io/otel/oteltest`. (#1229) +- OTLP Exporter updates: + - supports OTLP v0.6.0 (#1230, #1354) + - supports configurable aggregation temporality (default: Cumulative, optional: Stateless). (#1296) +- The Sampler is now called on local child spans. (#1233) +- The `Kind` type from the `go.opentelemetry.io/otel/api/metric` package was renamed to `InstrumentKind` to more specifically describe what it is and avoid semantic ambiguity. (#1240) +- The `MetricKind` method of the `Descriptor` type in the `go.opentelemetry.io/otel/api/metric` package was renamed to `Descriptor.InstrumentKind`. + This matches the returned type and fixes misuse of the term metric. (#1240) +- Move test harness from the `go.opentelemetry.io/otel/api/apitest` package into `go.opentelemetry.io/otel/oteltest`. (#1241) +- Move the `go.opentelemetry.io/otel/api/metric/metrictest` package into `go.opentelemetry.io/oteltest` as part of #964. (#1252) +- Move the `go.opentelemetry.io/otel/api/metric` package into `go.opentelemetry.io/otel/metric` as part of #1303. (#1321) +- Move the `go.opentelemetry.io/otel/api/metric/registry` package into `go.opentelemetry.io/otel/metric/registry` as a part of #1303. (#1316) +- Move the `Number` type (together with related functions) from `go.opentelemetry.io/otel/api/metric` package into `go.opentelemetry.io/otel/metric/number` as a part of #1303. (#1316) +- The function signature of the Span `AddEvent` method in `go.opentelemetry.io/otel` is updated to no longer take an unused context and instead take a required name and a variable number of `EventOption`s. (#1254) +- The function signature of the Span `RecordError` method in `go.opentelemetry.io/otel` is updated to no longer take an unused context and instead take a required error value and a variable number of `EventOption`s. (#1254) +- Move the `go.opentelemetry.io/otel/api/global` package to `go.opentelemetry.io/otel`. (#1262) (#1330) +- Move the `Version` function from `go.opentelemetry.io/otel/sdk` to `go.opentelemetry.io/otel`. (#1330) +- Rename correlation context header from `"otcorrelations"` to `"baggage"` to match the OpenTelemetry specification. (#1267) +- Fix `Code.UnmarshalJSON` to work with valid JSON only. (#1276) +- The `resource.New()` method changes signature to support builtin attributes and functional options, including `telemetry.sdk.*` and + `host.name` semantic conventions; the former method is renamed `resource.NewWithAttributes`. (#1235) +- The Prometheus exporter now exports non-monotonic counters (i.e. `UpDownCounter`s) as gauges. (#1210) +- Correct the `Span.End` method documentation in the `otel` API to state updates are not allowed on a span after it has ended. (#1310) +- Updated span collection limits for attribute, event and link counts to 1000 (#1318) +- Renamed `semconv.HTTPUrlKey` to `semconv.HTTPURLKey`. (#1338) + +### Removed + +- The `ErrInvalidHexID`, `ErrInvalidTraceIDLength`, `ErrInvalidSpanIDLength`, `ErrInvalidSpanIDLength`, or `ErrNilSpanID` from the `go.opentelemetry.io/otel` package are unexported now. (#1243) +- The `AddEventWithTimestamp` method on the `Span` interface in `go.opentelemetry.io/otel` is removed due to its redundancy. + It is replaced by using the `AddEvent` method with a `WithTimestamp` option. (#1254) +- The `MockSpan` and `MockTracer` types are removed from `go.opentelemetry.io/otel/oteltest`. + `Tracer` and `Span` from the same module should be used in their place instead. (#1306) +- `WorkerCount` option is removed from `go.opentelemetry.io/otel/exporters/otlp`. (#1350) +- Remove the following labels types: INT32, UINT32, UINT64 and FLOAT32. (#1314) + +### Fixed + +- Rename `MergeItererator` to `MergeIterator` in the `go.opentelemetry.io/otel/label` package. (#1244) +- The `go.opentelemetry.io/otel/api/global` packages global TextMapPropagator now delegates functionality to a globally set delegate for all previously returned propagators. (#1258) +- Fix condition in `label.Any`. (#1299) +- Fix global `TracerProvider` to pass options to its configured provider. (#1329) +- Fix missing handler for `ExactKind` aggregator in OTLP metrics transformer (#1309) + +## [0.13.0] - 2020-10-08 + +### Added + +- OTLP Metric exporter supports Histogram aggregation. (#1209) +- The `Code` struct from the `go.opentelemetry.io/otel/codes` package now supports JSON marshaling and unmarshaling as well as implements the `Stringer` interface. (#1214) +- A Baggage API to implement the OpenTelemetry specification. (#1217) +- Add Shutdown method to sdk/trace/provider, shutdown processors in the order they were registered. (#1227) + +### Changed + +- Set default propagator to no-op propagator. (#1184) +- The `HTTPSupplier`, `HTTPExtractor`, `HTTPInjector`, and `HTTPPropagator` from the `go.opentelemetry.io/otel/api/propagation` package were replaced with unified `TextMapCarrier` and `TextMapPropagator` in the `go.opentelemetry.io/otel/propagation` package. (#1212) (#1325) +- The `New` function from the `go.opentelemetry.io/otel/api/propagation` package was replaced with `NewCompositeTextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212) +- The status codes of the `go.opentelemetry.io/otel/codes` package have been updated to match the latest OpenTelemetry specification. + They now are `Unset`, `Error`, and `Ok`. + They no longer track the gRPC codes. (#1214) +- The `StatusCode` field of the `SpanData` struct in the `go.opentelemetry.io/otel/sdk/export/trace` package now uses the codes package from this package instead of the gRPC project. (#1214) +- Move the `go.opentelemetry.io/otel/api/baggage` package into `go.opentelemetry.io/otel/baggage`. (#1217) (#1325) +- A `Shutdown` method of `SpanProcessor` and all its implementations receives a context and returns an error. (#1264) + +### Fixed + +- Copies of data from arrays and slices passed to `go.opentelemetry.io/otel/label.ArrayValue()` are now used in the returned `Value` instead of using the mutable data itself. (#1226) + +### Removed + +- The `ExtractHTTP` and `InjectHTTP` functions from the `go.opentelemetry.io/otel/api/propagation` package were removed. (#1212) +- The `Propagators` interface from the `go.opentelemetry.io/otel/api/propagation` package was removed to conform to the OpenTelemetry specification. + The explicit `TextMapPropagator` type can be used in its place as this is the `Propagator` type the specification defines. (#1212) +- The `SetAttribute` method of the `Span` from the `go.opentelemetry.io/otel/api/trace` package was removed given its redundancy with the `SetAttributes` method. (#1216) +- The internal implementation of Baggage storage is removed in favor of using the new Baggage API functionality. (#1217) +- Remove duplicate hostname key `HostHostNameKey` in Resource semantic conventions. (#1219) +- Nested array/slice support has been removed. (#1226) + +## [0.12.0] - 2020-09-24 + +### Added + +- A `SpanConfigure` function in `go.opentelemetry.io/otel/api/trace` to create a new `SpanConfig` from `SpanOption`s. (#1108) +- In the `go.opentelemetry.io/otel/api/trace` package, `NewTracerConfig` was added to construct new `TracerConfig`s. + This addition was made to conform with our project option conventions. (#1155) +- Instrumentation library information was added to the Zipkin exporter. (#1119) +- The `SpanProcessor` interface now has a `ForceFlush()` method. (#1166) +- More semantic conventions for k8s as resource attributes. (#1167) + +### Changed + +- Add reconnecting udp connection type to Jaeger exporter. + This change adds a new optional implementation of the udp conn interface used to detect changes to an agent's host dns record. + It then adopts the new destination address to ensure the exporter doesn't get stuck. This change was ported from jaegertracing/jaeger-client-go#520. (#1063) +- Replace `StartOption` and `EndOption` in `go.opentelemetry.io/otel/api/trace` with `SpanOption`. + This change is matched by replacing the `StartConfig` and `EndConfig` with a unified `SpanConfig`. (#1108) +- Replace the `LinkedTo` span option in `go.opentelemetry.io/otel/api/trace` with `WithLinks`. + This is be more consistent with our other option patterns, i.e. passing the item to be configured directly instead of its component parts, and provides a cleaner function signature. (#1108) +- The `go.opentelemetry.io/otel/api/trace` `TracerOption` was changed to an interface to conform to project option conventions. (#1109) +- Move the `B3` and `TraceContext` from within the `go.opentelemetry.io/otel/api/trace` package to their own `go.opentelemetry.io/otel/propagators` package. + This removal of the propagators is reflective of the OpenTelemetry specification for these propagators as well as cleans up the `go.opentelemetry.io/otel/api/trace` API. (#1118) +- Rename Jaeger tags used for instrumentation library information to reflect changes in OpenTelemetry specification. (#1119) +- Rename `ProbabilitySampler` to `TraceIDRatioBased` and change semantics to ignore parent span sampling status. (#1115) +- Move `tools` package under `internal`. (#1141) +- Move `go.opentelemetry.io/otel/api/correlation` package to `go.opentelemetry.io/otel/api/baggage`. (#1142) + The `correlation.CorrelationContext` propagator has been renamed `baggage.Baggage`. Other exported functions and types are unchanged. +- Rename `ParentOrElse` sampler to `ParentBased` and allow setting samplers depending on parent span. (#1153) +- In the `go.opentelemetry.io/otel/api/trace` package, `SpanConfigure` was renamed to `NewSpanConfig`. (#1155) +- Change `dependabot.yml` to add a `Skip Changelog` label to dependabot-sourced PRs. (#1161) +- The [configuration style guide](https://github.com/open-telemetry/opentelemetry-go/blob/master/CONTRIBUTING.md#config) has been updated to + recommend the use of `newConfig()` instead of `configure()`. (#1163) +- The `otlp.Config` type has been unexported and changed to `otlp.config`, along with its initializer. (#1163) +- Ensure exported interface types include parameter names and update the + Style Guide to reflect this styling rule. (#1172) +- Don't consider unset environment variable for resource detection to be an error. (#1170) +- Rename `go.opentelemetry.io/otel/api/metric.ConfigureInstrument` to `NewInstrumentConfig` and + `go.opentelemetry.io/otel/api/metric.ConfigureMeter` to `NewMeterConfig`. +- ValueObserver instruments use LastValue aggregator by default. (#1165) +- OTLP Metric exporter supports LastValue aggregation. (#1165) +- Move the `go.opentelemetry.io/otel/api/unit` package to `go.opentelemetry.io/otel/unit`. (#1185) +- Rename `Provider` to `MeterProvider` in the `go.opentelemetry.io/otel/api/metric` package. (#1190) +- Rename `NoopProvider` to `NoopMeterProvider` in the `go.opentelemetry.io/otel/api/metric` package. (#1190) +- Rename `NewProvider` to `NewMeterProvider` in the `go.opentelemetry.io/otel/api/metric/metrictest` package. (#1190) +- Rename `Provider` to `MeterProvider` in the `go.opentelemetry.io/otel/api/metric/registry` package. (#1190) +- Rename `NewProvider` to `NewMeterProvider` in the `go.opentelemetry.io/otel/api/metri/registryc` package. (#1190) +- Rename `Provider` to `TracerProvider` in the `go.opentelemetry.io/otel/api/trace` package. (#1190) +- Rename `NoopProvider` to `NoopTracerProvider` in the `go.opentelemetry.io/otel/api/trace` package. (#1190) +- Rename `Provider` to `TracerProvider` in the `go.opentelemetry.io/otel/api/trace/tracetest` package. (#1190) +- Rename `NewProvider` to `NewTracerProvider` in the `go.opentelemetry.io/otel/api/trace/tracetest` package. (#1190) +- Rename `WrapperProvider` to `WrapperTracerProvider` in the `go.opentelemetry.io/otel/bridge/opentracing` package. (#1190) +- Rename `NewWrapperProvider` to `NewWrapperTracerProvider` in the `go.opentelemetry.io/otel/bridge/opentracing` package. (#1190) +- Rename `Provider` method of the pull controller to `MeterProvider` in the `go.opentelemetry.io/otel/sdk/metric/controller/pull` package. (#1190) +- Rename `Provider` method of the push controller to `MeterProvider` in the `go.opentelemetry.io/otel/sdk/metric/controller/push` package. (#1190) +- Rename `ProviderOptions` to `TracerProviderConfig` in the `go.opentelemetry.io/otel/sdk/trace` package. (#1190) +- Rename `ProviderOption` to `TracerProviderOption` in the `go.opentelemetry.io/otel/sdk/trace` package. (#1190) +- Rename `Provider` to `TracerProvider` in the `go.opentelemetry.io/otel/sdk/trace` package. (#1190) +- Rename `NewProvider` to `NewTracerProvider` in the `go.opentelemetry.io/otel/sdk/trace` package. (#1190) +- Renamed `SamplingDecision` values to comply with OpenTelemetry specification change. (#1192) +- Renamed Zipkin attribute names from `ot.status_code & ot.status_description` to `otel.status_code & otel.status_description`. (#1201) +- The default SDK now invokes registered `SpanProcessor`s in the order they were registered with the `TracerProvider`. (#1195) +- Add test of spans being processed by the `SpanProcessor`s in the order they were registered. (#1203) + +### Removed + +- Remove the B3 propagator from `go.opentelemetry.io/otel/propagators`. It is now located in the + `go.opentelemetry.io/contrib/propagators/` module. (#1191) +- Remove the semantic convention for HTTP status text, `HTTPStatusTextKey` from package `go.opentelemetry.io/otel/semconv`. (#1194) + +### Fixed + +- Zipkin example no longer mentions `ParentSampler`, corrected to `ParentBased`. (#1171) +- Fix missing shutdown processor in otel-collector example. (#1186) +- Fix missing shutdown processor in basic and namedtracer examples. (#1197) + ## [0.11.0] - 2020-08-24 ### Added +- Support for exporting array-valued attributes via OTLP. (#992) - `Noop` and `InMemory` `SpanBatcher` implementations to help with testing integrations. (#994) -- Integration tests for more OTel Collector Attribute types. (#1062) -- A dimensionality-reducing metric Processor. (#1057) - Support for filtering metric label sets. (#1047) -- Support for exporting array-valued attributes via OTLP. (#992) +- A dimensionality-reducing metric Processor. (#1057) +- Integration tests for more OTel Collector Attribute types. (#1062) +- A new `WithSpanProcessor` `ProviderOption` is added to the `go.opentelemetry.io/otel/sdk/trace` package to create a `Provider` and automatically register the `SpanProcessor`. (#1078) ### Changed @@ -35,6 +535,13 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Unify Callback Function Naming. Rename `*Callback` with `*Func`. (#1061) - CI builds validate against last two versions of Go, dropping 1.13 and adding 1.15. (#1064) +- The `go.opentelemetry.io/otel/sdk/export/trace` interfaces `SpanSyncer` and `SpanBatcher` have been replaced with a specification compliant `Exporter` interface. + This interface still supports the export of `SpanData`, but only as a slice. + Implementation are also required now to return any error from `ExportSpans` if one occurs as well as implement a `Shutdown` method for exporter clean-up. (#1078) +- The `go.opentelemetry.io/otel/sdk/trace` `NewBatchSpanProcessor` function no longer returns an error. + If a `nil` exporter is passed as an argument to this function, instead of it returning an error, it now returns a `BatchSpanProcessor` that handles the export of `SpanData` by not taking any action. (#1078) +- The `go.opentelemetry.io/otel/sdk/trace` `NewProvider` function to create a `Provider` no longer returns an error, instead only a `*Provider`. + This change is related to `NewBatchSpanProcessor` not returning an error which was the only error this function would return. (#1078) ### Removed @@ -780,7 +1287,16 @@ It contains api and sdk for trace and meter. - CODEOWNERS file to track owners of this project. -[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v0.11.0...HEAD +[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v0.20.0...HEAD +[0.20.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.20.0 +[0.19.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.19.0 +[0.18.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.18.0 +[0.17.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.17.0 +[0.16.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.16.0 +[0.15.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.15.0 +[0.14.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.14.0 +[0.13.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.13.0 +[0.12.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.12.0 [0.11.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.11.0 [0.10.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.10.0 [0.9.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.9.0 diff --git a/vendor/go.opentelemetry.io/otel/CODEOWNERS b/vendor/go.opentelemetry.io/otel/CODEOWNERS index cbca5922afc6..196df9cfd896 100644 --- a/vendor/go.opentelemetry.io/otel/CODEOWNERS +++ b/vendor/go.opentelemetry.io/otel/CODEOWNERS @@ -5,13 +5,13 @@ ##################################################### # # Learn about membership in OpenTelemetry community: -# https://github.com/open-telemetry/community/blob/master/community-membership.md -# +# https://github.com/open-telemetry/community/blob/main/community-membership.md # -# Learn about CODEOWNERS file format: +# +# Learn about CODEOWNERS file format: # https://help.github.com/en/articles/about-code-owners # -* @jmacd @lizthegrey @MrAlias @Aneurysm9 @evantorrie +* @jmacd @MrAlias @Aneurysm9 @evantorrie @XSAM @dashpole @paivagustavo CODEOWNERS @MrAlias @Aneurysm9 diff --git a/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md b/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md index 0059076af35a..51ab52c6384c 100644 --- a/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md +++ b/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md @@ -9,7 +9,7 @@ See the [public meeting notes](https://docs.google.com/document/d/1A63zSWX0x2CyCK_LoNhmQC4rqhLpYXJzXbEPDUQ2n6w/edit#heading=h.9tngw7jdwd6b) for a summary description of past meetings. To request edit access, join the meeting or get in touch on -[Gitter](https://gitter.im/open-telemetry/opentelemetry-go). +[Slack](https://cloud-native.slack.com/archives/C01NPAXACKT). ## Development @@ -19,6 +19,8 @@ You can view and edit the source code by cloning this repository: git clone https://github.com/open-telemetry/opentelemetry-go.git ``` +Run `make test` to run the tests instead of `go test`. + There are some generated files checked into the repo. To make sure that the generated files are up-to-date, run `make` (or `make precommit` - the `precommit` target is the default). @@ -95,19 +97,26 @@ request ID to the entry you added to `CHANGELOG.md`. A PR is considered to be **ready to merge** when: * It has received two approvals from Collaborators/Maintainers (at - different companies). -* Major feedbacks are resolved. + different companies). This is not enforced through technical means + and a PR may be **ready to merge** with a single approval if the change + and its approach have been discussed and consensus reached. +* Feedback has been addressed. +* Any substantive changes to your PR will require that you clear any prior + Approval reviews, this includes changes resulting from other feedback. Unless + the approver explicitly stated that their approval will persist across + changes it should be assumed that the PR needs their review again. Other + project members (e.g. approvers, maintainers) can help with this if there are + any questions or if you forget to clear reviews. * It has been open for review for at least one working day. This gives people reasonable time to review. -* Trivial change (typo, cosmetic, doc, etc.) doesn't have to wait for - one day. +* Trivial changes (typo, cosmetic, doc, etc.) do not have to wait for + one day and may be merged with a single Maintainer's approval. * `CHANGELOG.md` has been updated to reflect what has been added, changed, removed, or fixed. * Urgent fix can take exception as long as it has been actively communicated. -Any Collaborator/Maintainer can merge the PR once it is **ready to -merge**. +Any Maintainer can merge the PR once it is **ready to merge**. ## Design Choices @@ -115,7 +124,7 @@ As with other OpenTelemetry clients, opentelemetry-go follows the [opentelemetry-specification](https://github.com/open-telemetry/opentelemetry-specification). It's especially valuable to read through the [library -guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/library-guidelines.md). +guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/library-guidelines.md). ### Focus on Capabilities, Not Structure Compliance @@ -184,13 +193,13 @@ how the user can extend the configuration. It is important that `config` are not shared across package boundaries. Meaning a `config` from one package should not be directly used by another. -Optionally, it is common to include a `configure` function (with the same +Optionally, it is common to include a `newConfig` function (with the same naming scheme). This function wraps any defaults setting and looping over all options to create a configured `config`. ```go -// configure returns an appropriately configured config. -func configure([]Option) config { +// newConfig returns an appropriately configured config. +func newConfig([]Option) config { // Set default values for config. config := config{/* […] */} for _, option := range options { @@ -206,7 +215,7 @@ error as well that is expected to be handled by the instantiation function or propagated to the user. Given the design goal of not having the user need to work with the `config`, -the `configure` function should also be unexported. +the `newConfig` function should also be unexported. #### `Option` @@ -215,7 +224,7 @@ To set the value of the options a `config` contains, a corresponding ```go type Option interface { - Apply(*Config) + Apply(*config) } ``` @@ -241,7 +250,7 @@ func With*(…) Option { … } ```go type defaultFalseOption bool -func (o defaultFalseOption) Apply(c *Config) { +func (o defaultFalseOption) Apply(c *config) { c.Bool = bool(o) } @@ -254,7 +263,7 @@ func WithOption() Option { ```go type defaultTrueOption bool -func (o defaultTrueOption) Apply(c *Config) { +func (o defaultTrueOption) Apply(c *config) { c.Bool = bool(o) } @@ -271,7 +280,7 @@ type myTypeOption struct { MyType MyType } -func (o myTypeOption) Apply(c *Config) { +func (o myTypeOption) Apply(c *config) { c.MyType = o.MyType } @@ -342,20 +351,30 @@ func NewDog(name string, o ...DogOption) Dog {…} func NewBird(name string, o ...BirdOption) Bird {…} ``` +### Interface Type + +To allow other developers to better comprehend the code, it is important +to ensure it is sufficiently documented. One simple measure that contributes +to this aim is self-documenting by naming method parameters. Therefore, +where appropriate, methods of every exported interface type should have +their parameters appropriately named. + ## Approvers and Maintainers Approvers: -- [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb - [Evan Torrie](https://github.com/evantorrie), Verizon Media - [Josh MacDonald](https://github.com/jmacd), LightStep +- [Sam Xie](https://github.com/XSAM) +- [David Ashpole](https://github.com/dashpole), Google +- [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep Maintainers: -- [Anthony Mirabella](https://github.com/Aneurysm9), Centene -- [Tyler Yahn](https://github.com/MrAlias), New Relic +- [Anthony Mirabella](https://github.com/Aneurysm9), AWS +- [Tyler Yahn](https://github.com/MrAlias), Splunk ### Become an Approver or a Maintainer See the [community membership document in OpenTelemetry community -repo](https://github.com/open-telemetry/community/blob/master/community-membership.md). +repo](https://github.com/open-telemetry/community/blob/main/community-membership.md). diff --git a/vendor/go.opentelemetry.io/otel/Makefile b/vendor/go.opentelemetry.io/otel/Makefile index 9156960cabac..b290b667101a 100644 --- a/vendor/go.opentelemetry.io/otel/Makefile +++ b/vendor/go.opentelemetry.io/otel/Makefile @@ -13,145 +13,167 @@ # limitations under the License. EXAMPLES := $(shell ./get_main_pkgs.sh ./example) -TOOLS_MOD_DIR := ./tools +TOOLS_MOD_DIR := ./internal/tools # All source code and documents. Used in spell check. ALL_DOCS := $(shell find . -name '*.md' -type f | sort) # All directories with go.mod files related to opentelemetry library. Used for building, testing and linting. -ALL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(shell find . -type f -name 'go.mod' -exec dirname {} \; | sort)) +ALL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(shell find . -type f -name 'go.mod' -exec dirname {} \; | egrep -v '^./example' | sort)) $(shell find ./example -type f -name 'go.mod' -exec dirname {} \; | sort) ALL_COVERAGE_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | egrep -v '^./example|^$(TOOLS_MOD_DIR)' | sort) -# Mac OS Catalina 10.5.x doesn't support 386. Hence skip 386 test -SKIP_386_TEST = false -UNAME_S := $(shell uname -s) -ifeq ($(UNAME_S),Darwin) - SW_VERS := $(shell sw_vers -productVersion) - ifeq ($(shell echo $(SW_VERS) | egrep '^(10.1[5-9]|1[1-9]|[2-9])'), $(SW_VERS)) - SKIP_386_TEST = true - endif -endif - -GOTEST_MIN = go test -timeout 30s -GOTEST = $(GOTEST_MIN) -race -GOTEST_WITH_COVERAGE = $(GOTEST) -coverprofile=coverage.out -covermode=atomic -coverpkg=./... +GO = go +TIMEOUT = 60 .DEFAULT_GOAL := precommit -.PHONY: precommit +.PHONY: precommit ci +precommit: dependabot-check license-check lint build examples test-default +ci: precommit check-clean-work-tree test-coverage -TOOLS_DIR := $(abspath ./.tools) +# Tools -$(TOOLS_DIR)/golangci-lint: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go - cd $(TOOLS_MOD_DIR) && \ - go build -o $(TOOLS_DIR)/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint +TOOLS = $(CURDIR)/.tools -$(TOOLS_DIR)/misspell: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go +$(TOOLS): + @mkdir -p $@ +$(TOOLS)/%: | $(TOOLS) cd $(TOOLS_MOD_DIR) && \ - go build -o $(TOOLS_DIR)/misspell github.com/client9/misspell/cmd/misspell + $(GO) build -o $@ $(PACKAGE) -$(TOOLS_DIR)/stringer: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go - cd $(TOOLS_MOD_DIR) && \ - go build -o $(TOOLS_DIR)/stringer golang.org/x/tools/cmd/stringer +CROSSLINK = $(TOOLS)/crosslink +$(TOOLS)/crosslink: PACKAGE=go.opentelemetry.io/otel/$(TOOLS_MOD_DIR)/crosslink -$(TOOLS_DIR)/gojq: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go - cd $(TOOLS_MOD_DIR) && \ - go build -o $(TOOLS_DIR)/gojq github.com/itchyny/gojq/cmd/gojq +GOLANGCI_LINT = $(TOOLS)/golangci-lint +$(TOOLS)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint -precommit: generate build lint examples test +MISSPELL = $(TOOLS)/misspell +$(TOOLS)/misspell: PACKAGE= github.com/client9/misspell/cmd/misspell -.PHONY: test-with-coverage -test-with-coverage: - set -e; \ - printf "" > coverage.txt; \ - for dir in $(ALL_COVERAGE_MOD_DIRS); do \ - echo "go test ./... + coverage in $${dir}"; \ - (cd "$${dir}" && \ - $(GOTEST_WITH_COVERAGE) ./... && \ - go tool cover -html=coverage.out -o coverage.html); \ - [ -f "$${dir}/coverage.out" ] && cat "$${dir}/coverage.out" >> coverage.txt; \ - done; \ - sed -i.bak -e '2,$$ { /^mode: /d; }' coverage.txt +STRINGER = $(TOOLS)/stringer +$(TOOLS)/stringer: PACKAGE=golang.org/x/tools/cmd/stringer +$(TOOLS)/gojq: PACKAGE=github.com/itchyny/gojq/cmd/gojq -.PHONY: ci -ci: precommit check-clean-work-tree license-check test-with-coverage test-386 +.PHONY: tools +tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(STRINGER) $(TOOLS)/gojq -.PHONY: check-clean-work-tree -check-clean-work-tree: - @if ! git diff --quiet; then \ - echo; \ - echo 'Working tree is not clean, did you forget to run "make precommit"?'; \ - echo; \ - git status; \ - exit 1; \ - fi -.PHONY: build -build: - # TODO: Fix this on windows. +# Build + +.PHONY: examples generate build +examples: + @set -e; for dir in $(EXAMPLES); do \ + echo "$(GO) build $${dir}/..."; \ + (cd "$${dir}" && \ + $(GO) build .); \ + done + +generate: $(STRINGER) set -e; for dir in $(ALL_GO_MOD_DIRS); do \ - echo "compiling all packages in $${dir}"; \ + echo "$(GO) generate $${dir}/..."; \ (cd "$${dir}" && \ - go build ./... && \ - go test -run xxxxxMatchNothingxxxxx ./... >/dev/null); \ + PATH="$(TOOLS):$${PATH}" $(GO) generate ./...); \ done -.PHONY: test -test: +build: generate + # Build all package code including testing code. set -e; for dir in $(ALL_GO_MOD_DIRS); do \ - echo "go test ./... + race in $${dir}"; \ + echo "$(GO) build $${dir}/..."; \ (cd "$${dir}" && \ - $(GOTEST) ./...); \ + $(GO) build ./... && \ + $(GO) list ./... \ + | grep -v third_party \ + | xargs $(GO) test -vet=off -run xxxxxMatchNothingxxxxx >/dev/null); \ done -.PHONY: test-386 -test-386: - if [ $(SKIP_386_TEST) = true ] ; then \ - echo "skipping the test for GOARCH 386 as it is not supported on the current OS"; \ - else \ - set -e; for dir in $(ALL_GO_MOD_DIRS); do \ - echo "go test ./... GOARCH 386 in $${dir}"; \ - (cd "$${dir}" && \ - GOARCH=386 $(GOTEST_MIN) ./...); \ - done; \ - fi +# Tests -.PHONY: examples -examples: - @set -e; for ex in $(EXAMPLES); do \ - echo "Building $${ex}"; \ - (cd "$${ex}" && \ - go build .); \ +TEST_TARGETS := test-default test-bench test-short test-verbose test-race +.PHONY: $(TEST_TARGETS) test +test-default: ARGS=-v -race +test-bench: ARGS=-run=xxxxxMatchNothingxxxxx -test.benchtime=1ms -bench=. +test-short: ARGS=-short +test-verbose: ARGS=-v +test-race: ARGS=-race +$(TEST_TARGETS): test +test: + @set -e; for dir in $(ALL_GO_MOD_DIRS); do \ + echo "$(GO) test -timeout $(TIMEOUT)s $(ARGS) $${dir}/..."; \ + (cd "$${dir}" && \ + $(GO) list ./... \ + | grep -v third_party \ + | xargs $(GO) test -timeout $(TIMEOUT)s $(ARGS)); \ done +COVERAGE_MODE = atomic +COVERAGE_PROFILE = coverage.out +.PHONY: test-coverage +test-coverage: + @set -e; \ + printf "" > coverage.txt; \ + for dir in $(ALL_COVERAGE_MOD_DIRS); do \ + echo "$(GO) test -coverpkg=./... -covermode=$(COVERAGE_MODE) -coverprofile="$(COVERAGE_PROFILE)" $${dir}/..."; \ + (cd "$${dir}" && \ + $(GO) list ./... \ + | grep -v third_party \ + | xargs $(GO) test -coverpkg=./... -covermode=$(COVERAGE_MODE) -coverprofile="$(COVERAGE_PROFILE)" && \ + $(GO) tool cover -html=coverage.out -o coverage.html); \ + [ -f "$${dir}/coverage.out" ] && cat "$${dir}/coverage.out" >> coverage.txt; \ + done; \ + sed -i.bak -e '2,$$ { /^mode: /d; }' coverage.txt + .PHONY: lint -lint: $(TOOLS_DIR)/golangci-lint $(TOOLS_DIR)/misspell +lint: misspell lint-modules | $(GOLANGCI_LINT) set -e; for dir in $(ALL_GO_MOD_DIRS); do \ echo "golangci-lint in $${dir}"; \ (cd "$${dir}" && \ - $(TOOLS_DIR)/golangci-lint run --fix && \ - $(TOOLS_DIR)/golangci-lint run); \ - done - $(TOOLS_DIR)/misspell -w $(ALL_DOCS) - set -e; for dir in $(ALL_GO_MOD_DIRS) $(TOOLS_MOD_DIR); do \ - echo "go mod tidy in $${dir}"; \ - (cd "$${dir}" && \ - go mod tidy); \ + $(GOLANGCI_LINT) run --fix && \ + $(GOLANGCI_LINT) run); \ done -generate: $(TOOLS_DIR)/stringer - set -e; for dir in $(ALL_GO_MOD_DIRS); do \ - echo "running generators in $${dir}"; \ +.PHONY: misspell +misspell: | $(MISSPELL) + $(MISSPELL) -w $(ALL_DOCS) + +.PHONY: lint-modules +lint-modules: | $(CROSSLINK) + set -e; for dir in $(ALL_GO_MOD_DIRS) $(TOOLS_MOD_DIR); do \ + echo "$(GO) mod tidy in $${dir}"; \ (cd "$${dir}" && \ - PATH="$(TOOLS_DIR):$${PATH}" go generate ./...); \ + $(GO) mod tidy); \ done + echo "cross-linking all go modules" + $(CROSSLINK) .PHONY: license-check license-check: - @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path './vendor/*' ! -path './exporters/otlp/internal/opentelemetry-proto/*') ; do \ + @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*' ! -path './exporters/otlp/internal/opentelemetry-proto/*') ; do \ awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=3 { found=1; next } END { if (!found) print FILENAME }' $$f; \ done); \ if [ -n "$${licRes}" ]; then \ echo "license header checking failed:"; echo "$${licRes}"; \ exit 1; \ fi + +.PHONY: dependabot-check +dependabot-check: + @result=$$( \ + for f in $$( find . -type f -name go.mod -exec dirname {} \; | sed 's/^.\/\?/\//' ); \ + do grep -q "$$f" .github/dependabot.yml \ + || echo "$$f"; \ + done; \ + ); \ + if [ -n "$$result" ]; then \ + echo "missing go.mod dependabot check:"; echo "$$result"; \ + exit 1; \ + fi + +.PHONY: check-clean-work-tree +check-clean-work-tree: + @if ! git diff --quiet; then \ + echo; \ + echo 'Working tree is not clean, did you forget to run "make precommit"?'; \ + echo; \ + git status; \ + exit 1; \ + fi diff --git a/vendor/go.opentelemetry.io/otel/Makefile.proto b/vendor/go.opentelemetry.io/otel/Makefile.proto deleted file mode 100644 index 417c3b31c474..000000000000 --- a/vendor/go.opentelemetry.io/otel/Makefile.proto +++ /dev/null @@ -1,72 +0,0 @@ -# -*- mode: makefile; -*- -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This Makefile.proto has rules to generate *.pb.go files in -# `exporters/otlp/internal/opentelemetry-proto-gen` from the .proto files in -# `exporters/otlp/internal/opentelemetry-proto` using protoc with a go plugin. -# -# The protoc binary and other tools are sourced from a docker image -# `PROTOC_IMAGE`. -# -# Prereqs: The archiving utility `pax` is installed. - -PROTOC_IMAGE := namely/protoc-all:1.29_2 -PROTOBUF_VERSION := v1 -OTEL_PROTO_SUBMODULE := exporters/otlp/internal/opentelemetry-proto -PROTOBUF_GEN_DIR := exporters/otlp/internal/opentelemetry-proto-gen -PROTOBUF_TEMP_DIR := gen/pb-go -PROTO_SOURCE_DIR := gen/proto -SUBMODULE_PROTO_FILES := $(wildcard $(OTEL_PROTO_SUBMODULE)/opentelemetry/proto/*/$(PROTOBUF_VERSION)/*.proto \ - $(OTEL_PROTO_SUBMODULE)/opentelemetry/proto/collector/*/$(PROTOBUF_VERSION)/*.proto) -SOURCE_PROTO_FILES := $(subst $(OTEL_PROTO_SUBMODULE),$(PROTO_SOURCE_DIR),$(SUBMODULE_PROTO_FILES)) - -default: protobuf - -.PHONY: protobuf protobuf-source gen-protobuf copy-protobufs -protobuf: protobuf-source gen-protobuf copy-protobufs - -protobuf-source: $(SOURCE_PROTO_FILES) | $(PROTO_SOURCE_DIR)/ - -# Changes go_package in .proto file to point to repo-local location -define exec-replace-pkgname -sed 's,go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go,go_package = "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen,' < $(1) > $(2) - -endef - -# replace opentelemetry-proto package name by go.opentelemetry.io/otel specific version -$(SOURCE_PROTO_FILES): $(PROTO_SOURCE_DIR)/%.proto: $(OTEL_PROTO_SUBMODULE)/%.proto - @mkdir -p $(@D) - $(call exec-replace-pkgname,$<,$@) - -# Command to run protoc using docker image -define exec-protoc-all -docker run -v `pwd`:/defs $(PROTOC_IMAGE) $(1) - -endef - -gen-protobuf: $(SOURCE_PROTO_FILES) | $(PROTOBUF_GEN_DIR)/ - $(foreach file,$(subst ${PROTO_SOURCE_DIR}/,,$(SOURCE_PROTO_FILES)),$(call exec-protoc-all, -i $(PROTO_SOURCE_DIR) -f ${file} -l gogo -o ${PROTOBUF_TEMP_DIR})) - -# requires `pax` to be installed, as it has consistent options for both BSD (Darwin) and Linux -copy-protobufs: | $(PROTOBUF_GEN_DIR)/ - find ./$(PROTOBUF_TEMP_DIR)/go.opentelemetry.io/otel/$(PROTOBUF_GEN_DIR) -type f -print0 | \ - pax -0 -s ',^./$(PROTOBUF_TEMP_DIR)/go.opentelemetry.io/otel/$(PROTOBUF_GEN_DIR),,' -rw ./$(PROTOBUF_GEN_DIR) - -$(PROTO_SOURCE_DIR)/ $(PROTOBUF_GEN_DIR)/: - mkdir -p $@ - -.PHONY: clean -clean: - rm -rf ./gen diff --git a/vendor/go.opentelemetry.io/otel/README.md b/vendor/go.opentelemetry.io/otel/README.md index 55dbe2133dc8..c841ba896e56 100644 --- a/vendor/go.opentelemetry.io/otel/README.md +++ b/vendor/go.opentelemetry.io/otel/README.md @@ -1,80 +1,92 @@ # OpenTelemetry-Go -[![Circle CI](https://circleci.com/gh/open-telemetry/opentelemetry-go.svg?style=svg)](https://circleci.com/gh/open-telemetry/opentelemetry-go) -[![Docs](https://godoc.org/go.opentelemetry.io/otel?status.svg)](https://pkg.go.dev/go.opentelemetry.io/otel) +[![CI](https://github.com/open-telemetry/opentelemetry-go/workflows/ci/badge.svg)](https://github.com/open-telemetry/opentelemetry-go/actions?query=workflow%3Aci+branch%3Amain) +[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel)](https://pkg.go.dev/go.opentelemetry.io/otel) [![Go Report Card](https://goreportcard.com/badge/go.opentelemetry.io/otel)](https://goreportcard.com/report/go.opentelemetry.io/otel) -[![Gitter](https://badges.gitter.im/open-telemetry/opentelemetry-go.svg)](https://gitter.im/open-telemetry/opentelemetry-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![Slack](https://img.shields.io/badge/slack-@cncf/otel--go-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C01NPAXACKT) -The Go [OpenTelemetry](https://opentelemetry.io/) client. -## Installation +The Go [OpenTelemetry](https://opentelemetry.io/) implementation. -This repository includes multiple packages. The `api` -package contains core data types, interfaces and no-op implementations that comprise the OpenTelemetry API following -[the -specification](https://github.com/open-telemetry/opentelemetry-specification). -The `sdk` package is the reference implementation of the API. +## Project Status -Libraries that produce telemetry data should only depend on `api` -and defer the choice of the SDK to the application developer. Applications may -depend on `sdk` or another package that implements the API. +**Warning**: this project is currently in a pre-GA phase. Backwards +incompatible changes may be introduced in subsequent minor version releases as +we work to track the evolving OpenTelemetry specification and user feedback. -All packages are published to [go.opentelemetry.io/otel](https://pkg.go.dev/go.opentelemetry.io/otel) and is the preferred location to import from. +Our progress towards a GA release candidate is tracked in [this project +board](https://github.com/orgs/open-telemetry/projects/5). This release +candidate will follow semantic versioning and will be released with a major +version greater than zero. -Additional resources: +Progress and status specific to this repository is tracked in our local +[project boards](https://github.com/open-telemetry/opentelemetry-go/projects) +and +[milestones](https://github.com/open-telemetry/opentelemetry-go/milestones). -- [Developing using Go Modules](https://blog.golang.org/using-go-modules) -- [Adding dependencies and installing them](https://golang.org/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) +Project versioning information and stability guarantees can be found in the +[versioning documentation](./VERSIONING.md). -## Quick Start +### Compatibility -Below is a brief example of importing OpenTelemetry, initializing a tracer and creating some simple spans. +This project is tested on the following systems. -```go -package main +| OS | Go Version | Architecture | +| ------- | ---------- | ------------ | +| Ubuntu | 1.15 | amd64 | +| Ubuntu | 1.14 | amd64 | +| Ubuntu | 1.15 | 386 | +| Ubuntu | 1.14 | 386 | +| MacOS | 1.15 | amd64 | +| MacOS | 1.14 | amd64 | +| Windows | 1.15 | amd64 | +| Windows | 1.14 | amd64 | +| Windows | 1.15 | 386 | +| Windows | 1.14 | 386 | -import ( - "context" - "log" +While this project should work for other systems, no compatibility guarantees +are made for those systems currently. - "go.opentelemetry.io/otel/api/global" - "go.opentelemetry.io/otel/exporters/stdout" - sdktrace "go.opentelemetry.io/otel/sdk/trace" -) +## Getting Started -func main() { - pusher, err := stdout.InstallNewPipeline(nil, nil) - if err != nil { - log.Fatal(err) - } - defer pusher.Stop() +You can find a getting started guide on [opentelemetry.io](https://opentelemetry.io/docs/go/getting-started/). - tracer := global.Tracer("ex.com/basic") - ctx, span := tracer.Start(context.Background(), "main") - defer span.End() - /* … */ -} -``` +OpenTelemetry's goal is to provide a single set of APIs to capture distributed +traces and metrics from your application and send them to an observability +platform. This project allows you to do just that for applications written in +Go. There are two steps to this process: instrument your application, and +configure an exporter. -See the [API -documentation](https://pkg.go.dev/go.opentelemetry.io/otel) for more -detail, and the -[opentelemetry examples](./example/). +### Instrumentation -## Compatible Exporters +To start capturing distributed traces and metric events from your application +it first needs to be instrumented. The easiest way to do this is by using an +instrumentation library for your code. Be sure to check out [the officially +supported instrumentation +libraries](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation). -See the Go packages depending upon -[sdk/export/trace](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/export/trace?tab=importedby) -and [sdk/export/metric](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/export/metric?tab=importedby) -for a list of all exporters compatible with OpenTelemetry's Go SDK. +If you need to extend the telemetry an instrumentation library provides or want +to build your own instrumentation for your application directly you will need +to use the +[go.opentelemetry.io/otel/api](https://pkg.go.dev/go.opentelemetry.io/otel/api) +package. The included [examples](./example/) are a good way to see some +practical uses of this process. -## Compatible Libraries +### Export -See the -[opentelemetry-go-contrib](https://github.com/open-telemetry/opentelemetry-go-contrib) -repo for packages that facilitates instrumenting other useful Go libraries -with opentelemetry-go for distributed tracing and monitoring. +Now that your application is instrumented to collect telemetry, it needs an +export pipeline to send that telemetry to an observability platform. + +You can find officially supported exporters [here](./exporters/) and in the +companion [contrib +repository](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/exporters/metric). +Additionally, there are many vendor specific or 3rd party exporters for +OpenTelemetry. These exporters are broken down by +[trace](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/export/trace?tab=importedby) +and +[metric](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/export/metric?tab=importedby) +support. ## Contributing -See the [contributing file](CONTRIBUTING.md). +See the [contributing documentation](CONTRIBUTING.md). diff --git a/vendor/go.opentelemetry.io/otel/RELEASING.md b/vendor/go.opentelemetry.io/otel/RELEASING.md index 0fba7f1756ac..71d23b47a546 100644 --- a/vendor/go.opentelemetry.io/otel/RELEASING.md +++ b/vendor/go.opentelemetry.io/otel/RELEASING.md @@ -13,7 +13,7 @@ Update go.mod for submodules to depend on the new release which will happen in t 2. Verify the changes. ``` - git diff master + git diff main ``` This should have changed the version for all modules to be ``. @@ -44,7 +44,7 @@ Failure to do so will leave things in a broken state. It is critical you make sure the version you push upstream is correct. [Failure to do so will lead to minor emergencies and tough to work around](https://github.com/open-telemetry/opentelemetry-go/issues/331). -1. Run the tag.sh script using the `` of the commit on the master branch for the merged Pull Request. +1. Run the tag.sh script using the `` of the commit on the main branch for the merged Pull Request. ``` ./tag.sh @@ -78,4 +78,4 @@ This ensures they build with the published release, not the local copy. ## Contrib Repository -Once verified be sure to [make a release for the `contrib` repository](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/master/RELEASING.md) that uses this release. +Once verified be sure to [make a release for the `contrib` repository](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/RELEASING.md) that uses this release. diff --git a/vendor/go.opentelemetry.io/otel/VERSIONING.md b/vendor/go.opentelemetry.io/otel/VERSIONING.md new file mode 100644 index 000000000000..3579b794ee97 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/VERSIONING.md @@ -0,0 +1,217 @@ +# Versioning + +This document describes the versioning policy for this repository. This policy +is designed so the following goals can be achieved. + +**Users are provided a codebase of value that is stable and secure.** + +## Policy + +* Versioning of this project will be idiomatic of a Go project using [Go + modules](https://github.com/golang/go/wiki/Modules). + * [Semantic import + versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning) + will be used. + * Versions will comply with [semver 2.0](https://semver.org/spec/v2.0.0.html). + * If a module is version `v2` or higher, the major version of the module + must be included as a `/vN` at the end of the module paths used in + `go.mod` files (e.g., `module go.opentelemetry.io/otel/v2`, `require + go.opentelemetry.io/otel/v2 v2.0.1`) and in the package import path + (e.g., `import "go.opentelemetry.io/otel/v2/trace"`). This includes the + paths used in `go get` commands (e.g., `go get + go.opentelemetry.io/otel/v2@v2.0.1`. Note there is both a `/v2` and a + `@v2.0.1` in that example. One way to think about it is that the module + name now includes the `/v2`, so include `/v2` whenever you are using the + module name). + * If a module is version `v0` or `v1`, do not include the major version in + either the module path or the import path. + * Modules will be used to encapsulate signals and components. + * Experimental modules still under active development will be versioned at + `v0` to imply the stability guarantee defined by + [semver](https://semver.org/spec/v2.0.0.html#spec-item-4). + + > Major version zero (0.y.z) is for initial development. Anything MAY + > change at any time. The public API SHOULD NOT be considered stable. + + * Mature modules for which we guarantee a stable public API will be versioned + with a major version greater than `v0`. + * The decision to make a module stable will be made on a case-by-case + basis by the maintainers of this project. + * Experimental modules will start their versioning at `v0.0.0` and will + increment their minor version when backwards incompatible changes are + released and increment their patch version when backwards compatible + changes are released. + * All stable modules that use the same major version number will use the + same entire version number. + * Stable modules may be released with an incremented minor or patch + version even though that module has not been changed, but rather so + that it will remain at the same version as other stable modules that + did undergo change. + * When an experimental module becomes stable a new stable module version + will be released and will include this now stable module. The new + stable module version will be an increment of the minor version number + and will be applied to all existing stable modules as well as the newly + stable module being released. +* Versioning of the associated [contrib + repository](https://github.com/open-telemetry/opentelemetry-go-contrib) of + this project will be idiomatic of a Go project using [Go + modules](https://github.com/golang/go/wiki/Modules). + * [Semantic import + versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning) + will be used. + * Versions will comply with [semver 2.0](https://semver.org/spec/v2.0.0.html). + * If a module is version `v2` or higher, the + major version of the module must be included as a `/vN` at the end of the + module paths used in `go.mod` files (e.g., `module + go.opentelemetry.io/contrib/instrumentation/host/v2`, `require + go.opentelemetry.io/contrib/instrumentation/host/v2 v2.0.1`) and in the + package import path (e.g., `import + "go.opentelemetry.io/contrib/instrumentation/host/v2"`). This includes + the paths used in `go get` commands (e.g., `go get + go.opentelemetry.io/contrib/instrumentation/host/v2@v2.0.1`. Note there + is both a `/v2` and a `@v2.0.1` in that example. One way to think about + it is that the module name now includes the `/v2`, so include `/v2` + whenever you are using the module name). + * If a module is version `v0` or `v1`, do not include the major version + in either the module path or the import path. + * In addition to public APIs, telemetry produced by stable instrumentation + will remain stable and backwards compatible. This is to avoid breaking + alerts and dashboard. + * Modules will be used to encapsulate instrumentation, detectors, exporters, + propagators, and any other independent sets of related components. + * Experimental modules still under active development will be versioned at + `v0` to imply the stability guarantee defined by + [semver](https://semver.org/spec/v2.0.0.html#spec-item-4). + + > Major version zero (0.y.z) is for initial development. Anything MAY + > change at any time. The public API SHOULD NOT be considered stable. + + * Mature modules for which we guarantee a stable public API and telemetry will + be versioned with a major version greater than `v0`. + * Experimental modules will start their versioning at `v0.0.0` and will + increment their minor version when backwards incompatible changes are + released and increment their patch version when backwards compatible + changes are released. + * Stable contrib modules cannot depend on experimental modules from this + project. + * All stable contrib modules of the same major version with this project + will use the same entire version as this project. + * Stable modules may be released with an incremented minor or patch + version even though that module's code has not been changed. Instead + the only change that will have been included is to have updated that + modules dependency on this project's stable APIs. + * When an experimental module in contrib becomes stable a new stable + module version will be released and will include this now stable + module. The new stable module version will be an increment of the minor + version number and will be applied to all existing stable contrib + modules, this project's modules, and the newly stable module being + released. + * Contrib modules will be kept up to date with this project's releases. + * Due to the dependency contrib modules will implicitly have on this + project's modules the release of stable contrib modules to match the + released version number will be staggered after this project's release. + There is no explicit time guarantee for how long after this projects + release the contrib release will be. Effort should be made to keep them + as close in time as possible. + * No additional stable release in this project can be made until the + contrib repository has a matching stable release. + * No release can be made in the contrib repository after this project's + stable release except for a stable release of the contrib repository. +* GitHub releases will be made for all releases. +* Go modules will be made available at Go package mirrors. + +## Example Versioning Lifecycle + +To better understand the implementation of the above policy the following +example is provided. This project is simplified to include only the following +modules and their versions: + +* `otel`: `v0.14.0` +* `otel/trace`: `v0.14.0` +* `otel/metric`: `v0.14.0` +* `otel/baggage`: `v0.14.0` +* `otel/sdk/trace`: `v0.14.0` +* `otel/sdk/metric`: `v0.14.0` + +These modules have been developed to a point where the `otel/trace`, +`otel/baggage`, and `otel/sdk/trace` modules have reached a point that they +should be considered for a stable release. The `otel/metric` and +`otel/sdk/metric` are still under active development and the `otel` module +depends on both `otel/trace` and `otel/metric`. + +The `otel` package is refactored to remove its dependencies on `otel/metric` so +it can be released as stable as well. With that done the following release +candidates are made: + +* `otel`: `v1.0.0-rc.1` +* `otel/trace`: `v1.0.0-rc.1` +* `otel/baggage`: `v1.0.0-rc.1` +* `otel/sdk/trace`: `v1.0.0-rc.1` + +The `otel/metric` and `otel/sdk/metric` modules remain at `v0.14.0`. + +A few minor issues are discovered in the `otel/trace` package. These issues are +resolved with some minor, but backwards incompatible, changes and are released +as a second release candidate: + +* `otel`: `v1.0.0-rc.2` +* `otel/trace`: `v1.0.0-rc.2` +* `otel/baggage`: `v1.0.0-rc.2` +* `otel/sdk/trace`: `v1.0.0-rc.2` + +Notice that all module version numbers are incremented to adhere to our +versioning policy. + +After these release candidates have been evaluated to satisfaction, they are +released as version `v1.0.0`. + +* `otel`: `v1.0.0` +* `otel/trace`: `v1.0.0` +* `otel/baggage`: `v1.0.0` +* `otel/sdk/trace`: `v1.0.0` + +Since both the `go` utility and the Go module system support [the semantic +versioning definition of +precedence](https://semver.org/spec/v2.0.0.html#spec-item-11), this release +will correctly be interpreted as the successor to the previous release +candidates. + +Active development of this project continues. The `otel/metric` module now has +backwards incompatible changes to its API that need to be released and the +`otel/baggage` module has a minor bug fix that needs to be released. The +following release is made: + +* `otel`: `v1.0.1` +* `otel/trace`: `v1.0.1` +* `otel/metric`: `v0.15.0` +* `otel/baggage`: `v1.0.1` +* `otel/sdk/trace`: `v1.0.1` +* `otel/sdk/metric`: `v0.15.0` + +Notice that, again, all stable module versions are incremented in unison and +the `otel/sdk/metric` package, which depends on the `otel/metric` package, also +bumped its version. This bump of the `otel/sdk/metric` package makes sense +given their coupling, though it is not explicitly required by our versioning +policy. + +As we progress, the `otel/metric` and `otel/sdk/metric` packages have reached a +point where they should be evaluated for stability. The `otel` module is +reintegrated with the `otel/metric` package and the following release is made: + +* `otel`: `v1.1.0-rc.1` +* `otel/trace`: `v1.1.0-rc.1` +* `otel/metric`: `v1.1.0-rc.1` +* `otel/baggage`: `v1.1.0-rc.1` +* `otel/sdk/trace`: `v1.1.0-rc.1` +* `otel/sdk/metric`: `v1.1.0-rc.1` + +All the modules are evaluated and determined to a viable stable release. They +are then released as version `v1.1.0` (the minor version is incremented to +indicate the addition of new signal). + +* `otel`: `v1.1.0` +* `otel/trace`: `v1.1.0` +* `otel/metric`: `v1.1.0` +* `otel/baggage`: `v1.1.0` +* `otel/sdk/trace`: `v1.1.0` +* `otel/sdk/metric`: `v1.1.0` diff --git a/vendor/go.opentelemetry.io/otel/api/correlation/doc.go b/vendor/go.opentelemetry.io/otel/api/correlation/doc.go deleted file mode 100644 index 1147a4f3997f..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/correlation/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This package implements the correlation functionality as specified -// in the OpenTelemetry specification. Currently it provides a data -// structure for storing correlations (Map) and a way of putting Map -// object into the context and retrieving it from context. -package correlation // import "go.opentelemetry.io/otel/api/correlation" diff --git a/vendor/go.opentelemetry.io/otel/api/correlation/map.go b/vendor/go.opentelemetry.io/otel/api/correlation/map.go deleted file mode 100644 index df517da49865..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/correlation/map.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package correlation - -import "go.opentelemetry.io/otel/label" - -type rawMap map[label.Key]label.Value -type keySet map[label.Key]struct{} - -// Map is an immutable storage for correlations. -type Map struct { - m rawMap -} - -// MapUpdate contains information about correlation changes to be -// made. -type MapUpdate struct { - // DropSingleK contains a single key to be dropped from - // correlations. Use this to avoid an overhead of a slice - // allocation if there is only one key to drop. - DropSingleK label.Key - // DropMultiK contains all the keys to be dropped from - // correlations. - DropMultiK []label.Key - - // SingleKV contains a single key-value pair to be added to - // correlations. Use this to avoid an overhead of a slice - // allocation if there is only one key-value pair to add. - SingleKV label.KeyValue - // MultiKV contains all the key-value pairs to be added to - // correlations. - MultiKV []label.KeyValue -} - -func newMap(raw rawMap) Map { - return Map{ - m: raw, - } -} - -// NewEmptyMap creates an empty correlations map. -func NewEmptyMap() Map { - return newMap(nil) -} - -// NewMap creates a map with the contents of the update applied. In -// this function, having an update with DropSingleK or DropMultiK -// makes no sense - those fields are effectively ignored. -func NewMap(update MapUpdate) Map { - return NewEmptyMap().Apply(update) -} - -// Apply creates a copy of the map with the contents of the update -// applied. Apply will first drop the keys from DropSingleK and -// DropMultiK, then add key-value pairs from SingleKV and MultiKV. -func (m Map) Apply(update MapUpdate) Map { - delSet, addSet := getModificationSets(update) - mapSize := getNewMapSize(m.m, delSet, addSet) - - r := make(rawMap, mapSize) - for k, v := range m.m { - // do not copy items we want to drop - if _, ok := delSet[k]; ok { - continue - } - // do not copy items we would overwrite - if _, ok := addSet[k]; ok { - continue - } - r[k] = v - } - if update.SingleKV.Key.Defined() { - r[update.SingleKV.Key] = update.SingleKV.Value - } - for _, kv := range update.MultiKV { - r[kv.Key] = kv.Value - } - if len(r) == 0 { - r = nil - } - return newMap(r) -} - -func getModificationSets(update MapUpdate) (delSet, addSet keySet) { - deletionsCount := len(update.DropMultiK) - if update.DropSingleK.Defined() { - deletionsCount++ - } - if deletionsCount > 0 { - delSet = make(map[label.Key]struct{}, deletionsCount) - for _, k := range update.DropMultiK { - delSet[k] = struct{}{} - } - if update.DropSingleK.Defined() { - delSet[update.DropSingleK] = struct{}{} - } - } - - additionsCount := len(update.MultiKV) - if update.SingleKV.Key.Defined() { - additionsCount++ - } - if additionsCount > 0 { - addSet = make(map[label.Key]struct{}, additionsCount) - for _, k := range update.MultiKV { - addSet[k.Key] = struct{}{} - } - if update.SingleKV.Key.Defined() { - addSet[update.SingleKV.Key] = struct{}{} - } - } - - return -} - -func getNewMapSize(m rawMap, delSet, addSet keySet) int { - mapSizeDiff := 0 - for k := range addSet { - if _, ok := m[k]; !ok { - mapSizeDiff++ - } - } - for k := range delSet { - if _, ok := m[k]; ok { - if _, inAddSet := addSet[k]; !inAddSet { - mapSizeDiff-- - } - } - } - return len(m) + mapSizeDiff -} - -// Value gets a value from correlations map and returns a boolean -// value indicating whether the key exist in the map. -func (m Map) Value(k label.Key) (label.Value, bool) { - value, ok := m.m[k] - return value, ok -} - -// HasValue returns a boolean value indicating whether the key exist -// in the map. -func (m Map) HasValue(k label.Key) bool { - _, has := m.Value(k) - return has -} - -// Len returns a length of the map. -func (m Map) Len() int { - return len(m.m) -} - -// Foreach calls a passed callback once on each key-value pair until -// all the key-value pairs of the map were iterated or the callback -// returns false, whichever happens first. -func (m Map) Foreach(f func(label.KeyValue) bool) { - for k, v := range m.m { - if !f(label.KeyValue{ - Key: k, - Value: v, - }) { - return - } - } -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/async.go b/vendor/go.opentelemetry.io/otel/api/metric/async.go deleted file mode 100644 index d0d488df1305..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/async.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -import ( - "context" - - "go.opentelemetry.io/otel/label" -) - -// The file is organized as follows: -// -// - Observation type -// - Three kinds of Observer callback (int64, float64, batch) -// - Three kinds of Observer result (int64, float64, batch) -// - Three kinds of Observe() function (int64, float64, batch) -// - Three kinds of AsyncRunner interface (abstract, single, batch) -// - Two kinds of Observer constructor (int64, float64) -// - Two kinds of Observation() function (int64, float64) -// - Various internals - -// Observation is used for reporting an asynchronous batch of metric -// values. Instances of this type should be created by asynchronous -// instruments (e.g., Int64ValueObserver.Observation()). -type Observation struct { - // number needs to be aligned for 64-bit atomic operations. - number Number - instrument AsyncImpl -} - -// Int64ObserverFunc is a type of callback that integral -// observers run. -type Int64ObserverFunc func(context.Context, Int64ObserverResult) - -// Float64ObserverFunc is a type of callback that floating point -// observers run. -type Float64ObserverFunc func(context.Context, Float64ObserverResult) - -// BatchObserverFunc is a callback argument for use with any -// Observer instrument that will be reported as a batch of -// observations. -type BatchObserverFunc func(context.Context, BatchObserverResult) - -// Int64ObserverResult is passed to an observer callback to capture -// observations for one asynchronous integer metric instrument. -type Int64ObserverResult struct { - instrument AsyncImpl - function func([]label.KeyValue, ...Observation) -} - -// Float64ObserverResult is passed to an observer callback to capture -// observations for one asynchronous floating point metric instrument. -type Float64ObserverResult struct { - instrument AsyncImpl - function func([]label.KeyValue, ...Observation) -} - -// BatchObserverResult is passed to a batch observer callback to -// capture observations for multiple asynchronous instruments. -type BatchObserverResult struct { - function func([]label.KeyValue, ...Observation) -} - -// Observe captures a single integer value from the associated -// instrument callback, with the given labels. -func (ir Int64ObserverResult) Observe(value int64, labels ...label.KeyValue) { - ir.function(labels, Observation{ - instrument: ir.instrument, - number: NewInt64Number(value), - }) -} - -// Observe captures a single floating point value from the associated -// instrument callback, with the given labels. -func (fr Float64ObserverResult) Observe(value float64, labels ...label.KeyValue) { - fr.function(labels, Observation{ - instrument: fr.instrument, - number: NewFloat64Number(value), - }) -} - -// Observe captures a multiple observations from the associated batch -// instrument callback, with the given labels. -func (br BatchObserverResult) Observe(labels []label.KeyValue, obs ...Observation) { - br.function(labels, obs...) -} - -// AsyncRunner is expected to convert into an AsyncSingleRunner or an -// AsyncBatchRunner. SDKs will encounter an error if the AsyncRunner -// does not satisfy one of these interfaces. -type AsyncRunner interface { - // AnyRunner() is a non-exported method with no functional use - // other than to make this a non-empty interface. - AnyRunner() -} - -// AsyncSingleRunner is an interface implemented by single-observer -// callbacks. -type AsyncSingleRunner interface { - // Run accepts a single instrument and function for capturing - // observations of that instrument. Each call to the function - // receives one captured observation. (The function accepts - // multiple observations so the same implementation can be - // used for batch runners.) - Run(ctx context.Context, single AsyncImpl, capture func([]label.KeyValue, ...Observation)) - - AsyncRunner -} - -// AsyncBatchRunner is an interface implemented by batch-observer -// callbacks. -type AsyncBatchRunner interface { - // Run accepts a function for capturing observations of - // multiple instruments. - Run(ctx context.Context, capture func([]label.KeyValue, ...Observation)) - - AsyncRunner -} - -var _ AsyncSingleRunner = (*Int64ObserverFunc)(nil) -var _ AsyncSingleRunner = (*Float64ObserverFunc)(nil) -var _ AsyncBatchRunner = (*BatchObserverFunc)(nil) - -// newInt64AsyncRunner returns a single-observer callback for integer Observer instruments. -func newInt64AsyncRunner(c Int64ObserverFunc) AsyncSingleRunner { - return &c -} - -// newFloat64AsyncRunner returns a single-observer callback for floating point Observer instruments. -func newFloat64AsyncRunner(c Float64ObserverFunc) AsyncSingleRunner { - return &c -} - -// newBatchAsyncRunner returns a batch-observer callback use with multiple Observer instruments. -func newBatchAsyncRunner(c BatchObserverFunc) AsyncBatchRunner { - return &c -} - -// AnyRunner implements AsyncRunner. -func (*Int64ObserverFunc) AnyRunner() {} - -// AnyRunner implements AsyncRunner. -func (*Float64ObserverFunc) AnyRunner() {} - -// AnyRunner implements AsyncRunner. -func (*BatchObserverFunc) AnyRunner() {} - -// Run implements AsyncSingleRunner. -func (i *Int64ObserverFunc) Run(ctx context.Context, impl AsyncImpl, function func([]label.KeyValue, ...Observation)) { - (*i)(ctx, Int64ObserverResult{ - instrument: impl, - function: function, - }) -} - -// Run implements AsyncSingleRunner. -func (f *Float64ObserverFunc) Run(ctx context.Context, impl AsyncImpl, function func([]label.KeyValue, ...Observation)) { - (*f)(ctx, Float64ObserverResult{ - instrument: impl, - function: function, - }) -} - -// Run implements AsyncBatchRunner. -func (b *BatchObserverFunc) Run(ctx context.Context, function func([]label.KeyValue, ...Observation)) { - (*b)(ctx, BatchObserverResult{ - function: function, - }) -} - -// wrapInt64ValueObserverInstrument converts an AsyncImpl into Int64ValueObserver. -func wrapInt64ValueObserverInstrument(asyncInst AsyncImpl, err error) (Int64ValueObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Int64ValueObserver{asyncInstrument: common}, err -} - -// wrapFloat64ValueObserverInstrument converts an AsyncImpl into Float64ValueObserver. -func wrapFloat64ValueObserverInstrument(asyncInst AsyncImpl, err error) (Float64ValueObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Float64ValueObserver{asyncInstrument: common}, err -} - -// wrapInt64SumObserverInstrument converts an AsyncImpl into Int64SumObserver. -func wrapInt64SumObserverInstrument(asyncInst AsyncImpl, err error) (Int64SumObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Int64SumObserver{asyncInstrument: common}, err -} - -// wrapFloat64SumObserverInstrument converts an AsyncImpl into Float64SumObserver. -func wrapFloat64SumObserverInstrument(asyncInst AsyncImpl, err error) (Float64SumObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Float64SumObserver{asyncInstrument: common}, err -} - -// wrapInt64UpDownSumObserverInstrument converts an AsyncImpl into Int64UpDownSumObserver. -func wrapInt64UpDownSumObserverInstrument(asyncInst AsyncImpl, err error) (Int64UpDownSumObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Int64UpDownSumObserver{asyncInstrument: common}, err -} - -// wrapFloat64UpDownSumObserverInstrument converts an AsyncImpl into Float64UpDownSumObserver. -func wrapFloat64UpDownSumObserverInstrument(asyncInst AsyncImpl, err error) (Float64UpDownSumObserver, error) { - common, err := checkNewAsync(asyncInst, err) - return Float64UpDownSumObserver{asyncInstrument: common}, err -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/counter.go b/vendor/go.opentelemetry.io/otel/api/metric/counter.go deleted file mode 100644 index c03421d2a3f1..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/counter.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -import ( - "context" - - "go.opentelemetry.io/otel/label" -) - -// Float64Counter is a metric that accumulates float64 values. -type Float64Counter struct { - syncInstrument -} - -// Int64Counter is a metric that accumulates int64 values. -type Int64Counter struct { - syncInstrument -} - -// BoundFloat64Counter is a bound instrument for Float64Counter. -// -// It inherits the Unbind function from syncBoundInstrument. -type BoundFloat64Counter struct { - syncBoundInstrument -} - -// BoundInt64Counter is a boundInstrument for Int64Counter. -// -// It inherits the Unbind function from syncBoundInstrument. -type BoundInt64Counter struct { - syncBoundInstrument -} - -// Bind creates a bound instrument for this counter. The labels are -// associated with values recorded via subsequent calls to Record. -func (c Float64Counter) Bind(labels ...label.KeyValue) (h BoundFloat64Counter) { - h.syncBoundInstrument = c.bind(labels) - return -} - -// Bind creates a bound instrument for this counter. The labels are -// associated with values recorded via subsequent calls to Record. -func (c Int64Counter) Bind(labels ...label.KeyValue) (h BoundInt64Counter) { - h.syncBoundInstrument = c.bind(labels) - return -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Float64Counter) Measurement(value float64) Measurement { - return c.float64Measurement(value) -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Int64Counter) Measurement(value int64) Measurement { - return c.int64Measurement(value) -} - -// Add adds the value to the counter's sum. The labels should contain -// the keys and values to be associated with this value. -func (c Float64Counter) Add(ctx context.Context, value float64, labels ...label.KeyValue) { - c.directRecord(ctx, NewFloat64Number(value), labels) -} - -// Add adds the value to the counter's sum. The labels should contain -// the keys and values to be associated with this value. -func (c Int64Counter) Add(ctx context.Context, value int64, labels ...label.KeyValue) { - c.directRecord(ctx, NewInt64Number(value), labels) -} - -// Add adds the value to the counter's sum using the labels -// previously bound to this counter via Bind() -func (b BoundFloat64Counter) Add(ctx context.Context, value float64) { - b.directRecord(ctx, NewFloat64Number(value)) -} - -// Add adds the value to the counter's sum using the labels -// previously bound to this counter via Bind() -func (b BoundInt64Counter) Add(ctx context.Context, value int64) { - b.directRecord(ctx, NewInt64Number(value)) -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/descriptor.go b/vendor/go.opentelemetry.io/otel/api/metric/descriptor.go deleted file mode 100644 index ccc2e94b5c6f..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/descriptor.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -import "go.opentelemetry.io/otel/api/unit" - -// Descriptor contains all the settings that describe an instrument, -// including its name, metric kind, number kind, and the configurable -// options. -type Descriptor struct { - name string - kind Kind - numberKind NumberKind - config InstrumentConfig -} - -// NewDescriptor returns a Descriptor with the given contents. -func NewDescriptor(name string, mkind Kind, nkind NumberKind, opts ...InstrumentOption) Descriptor { - return Descriptor{ - name: name, - kind: mkind, - numberKind: nkind, - config: ConfigureInstrument(opts), - } -} - -// Name returns the metric instrument's name. -func (d Descriptor) Name() string { - return d.name -} - -// MetricKind returns the specific kind of instrument. -func (d Descriptor) MetricKind() Kind { - return d.kind -} - -// Description provides a human-readable description of the metric -// instrument. -func (d Descriptor) Description() string { - return d.config.Description -} - -// Unit describes the units of the metric instrument. Unitless -// metrics return the empty string. -func (d Descriptor) Unit() unit.Unit { - return d.config.Unit -} - -// NumberKind returns whether this instrument is declared over int64, -// float64, or uint64 values. -func (d Descriptor) NumberKind() NumberKind { - return d.numberKind -} - -// InstrumentationName returns the name of the library that provided -// instrumentation for this instrument. -func (d Descriptor) InstrumentationName() string { - return d.config.InstrumentationName -} - -// InstrumentationVersion returns the version of the library that provided -// instrumentation for this instrument. -func (d Descriptor) InstrumentationVersion() string { - return d.config.InstrumentationVersion -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/doc.go b/vendor/go.opentelemetry.io/otel/api/metric/doc.go deleted file mode 100644 index cda2159d0bac..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/doc.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// metric package provides an API for reporting diagnostic -// measurements using instruments categorized as follows: -// -// Synchronous instruments are called by the user with a Context. -// Asynchronous instruments are called by the SDK during collection. -// -// Additive instruments are semantically intended for capturing a sum. -// Non-additive instruments are intended for capturing a distribution. -// -// Additive instruments may be monotonic, in which case they are -// non-descreasing and naturally define a rate. -// -// The synchronous instrument names are: -// -// Counter: additive, monotonic -// UpDownCounter: additive -// ValueRecorder: non-additive -// -// and the asynchronous instruments are: -// -// SumObserver: additive, monotonic -// UpDownSumObserver: additive -// ValueObserver: non-additive -// -// All instruments are provided with support for either float64 or -// int64 input values. -// -// The Meter interface supports allocating new instruments as well as -// interfaces for recording batches of synchronous measurements or -// asynchronous observations. To obtain a Meter, use a Provider. -// -// The Provider interface supports obtaining a named Meter interface. -// To obtain a Provider implementation, initialize and configure any -// compatible SDK. -package metric // import "go.opentelemetry.io/otel/api/metric" diff --git a/vendor/go.opentelemetry.io/otel/api/metric/kind.go b/vendor/go.opentelemetry.io/otel/api/metric/kind.go deleted file mode 100644 index 9d4b453f3e56..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/kind.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:generate stringer -type=Kind - -package metric - -// Kind describes the kind of instrument. -type Kind int8 - -const ( - // ValueRecorderKind indicates a ValueRecorder instrument. - ValueRecorderKind Kind = iota - // ValueObserverKind indicates an ValueObserver instrument. - ValueObserverKind - - // CounterKind indicates a Counter instrument. - CounterKind - // UpDownCounterKind indicates a UpDownCounter instrument. - UpDownCounterKind - - // SumObserverKind indicates a SumObserver instrument. - SumObserverKind - // UpDownSumObserverKind indicates a UpDownSumObserver instrument. - UpDownSumObserverKind -) - -// Synchronous returns whether this is a synchronous kind of instrument. -func (k Kind) Synchronous() bool { - switch k { - case CounterKind, UpDownCounterKind, ValueRecorderKind: - return true - } - return false -} - -// Asynchronous returns whether this is an asynchronous kind of instrument. -func (k Kind) Asynchronous() bool { - return !k.Synchronous() -} - -// Adding returns whether this kind of instrument adds its inputs (as opposed to Grouping). -func (k Kind) Adding() bool { - switch k { - case CounterKind, UpDownCounterKind, SumObserverKind, UpDownSumObserverKind: - return true - } - return false -} - -// Adding returns whether this kind of instrument groups its inputs (as opposed to Adding). -func (k Kind) Grouping() bool { - return !k.Adding() -} - -// Monotonic returns whether this kind of instrument exposes a non-decreasing sum. -func (k Kind) Monotonic() bool { - switch k { - case CounterKind, SumObserverKind: - return true - } - return false -} - -// Cumulative returns whether this kind of instrument receives precomputed sums. -func (k Kind) PrecomputedSum() bool { - return k.Adding() && k.Asynchronous() -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/must.go b/vendor/go.opentelemetry.io/otel/api/metric/must.go deleted file mode 100644 index c88e050a38f9..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/must.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -// MeterMust is a wrapper for Meter interfaces that panics when any -// instrument constructor encounters an error. -type MeterMust struct { - meter Meter -} - -// BatchObserverMust is a wrapper for BatchObserver that panics when -// any instrument constructor encounters an error. -type BatchObserverMust struct { - batch BatchObserver -} - -// Must constructs a MeterMust implementation from a Meter, allowing -// the application to panic when any instrument constructor yields an -// error. -func Must(meter Meter) MeterMust { - return MeterMust{meter: meter} -} - -// NewInt64Counter calls `Meter.NewInt64Counter` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64Counter(name string, cos ...InstrumentOption) Int64Counter { - if inst, err := mm.meter.NewInt64Counter(name, cos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64Counter calls `Meter.NewFloat64Counter` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64Counter(name string, cos ...InstrumentOption) Float64Counter { - if inst, err := mm.meter.NewFloat64Counter(name, cos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64UpDownCounter calls `Meter.NewInt64UpDownCounter` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64UpDownCounter(name string, cos ...InstrumentOption) Int64UpDownCounter { - if inst, err := mm.meter.NewInt64UpDownCounter(name, cos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64UpDownCounter calls `Meter.NewFloat64UpDownCounter` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64UpDownCounter(name string, cos ...InstrumentOption) Float64UpDownCounter { - if inst, err := mm.meter.NewFloat64UpDownCounter(name, cos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64ValueRecorder calls `Meter.NewInt64ValueRecorder` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64ValueRecorder(name string, mos ...InstrumentOption) Int64ValueRecorder { - if inst, err := mm.meter.NewInt64ValueRecorder(name, mos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64ValueRecorder calls `Meter.NewFloat64ValueRecorder` and returns the -// instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64ValueRecorder(name string, mos ...InstrumentOption) Float64ValueRecorder { - if inst, err := mm.meter.NewFloat64ValueRecorder(name, mos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64ValueObserver calls `Meter.NewInt64ValueObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64ValueObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64ValueObserver { - if inst, err := mm.meter.NewInt64ValueObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64ValueObserver calls `Meter.NewFloat64ValueObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64ValueObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64ValueObserver { - if inst, err := mm.meter.NewFloat64ValueObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64SumObserver calls `Meter.NewInt64SumObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64SumObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64SumObserver { - if inst, err := mm.meter.NewInt64SumObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64SumObserver calls `Meter.NewFloat64SumObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64SumObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64SumObserver { - if inst, err := mm.meter.NewFloat64SumObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64UpDownSumObserver calls `Meter.NewInt64UpDownSumObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64UpDownSumObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64UpDownSumObserver { - if inst, err := mm.meter.NewInt64UpDownSumObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64UpDownSumObserver calls `Meter.NewFloat64UpDownSumObserver` and -// returns the instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64UpDownSumObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64UpDownSumObserver { - if inst, err := mm.meter.NewFloat64UpDownSumObserver(name, callback, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewBatchObserver returns a wrapper around BatchObserver that panics -// when any instrument constructor returns an error. -func (mm MeterMust) NewBatchObserver(callback BatchObserverFunc) BatchObserverMust { - return BatchObserverMust{ - batch: mm.meter.NewBatchObserver(callback), - } -} - -// NewInt64ValueObserver calls `BatchObserver.NewInt64ValueObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewInt64ValueObserver(name string, oos ...InstrumentOption) Int64ValueObserver { - if inst, err := bm.batch.NewInt64ValueObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64ValueObserver calls `BatchObserver.NewFloat64ValueObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewFloat64ValueObserver(name string, oos ...InstrumentOption) Float64ValueObserver { - if inst, err := bm.batch.NewFloat64ValueObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64SumObserver calls `BatchObserver.NewInt64SumObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewInt64SumObserver(name string, oos ...InstrumentOption) Int64SumObserver { - if inst, err := bm.batch.NewInt64SumObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64SumObserver calls `BatchObserver.NewFloat64SumObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewFloat64SumObserver(name string, oos ...InstrumentOption) Float64SumObserver { - if inst, err := bm.batch.NewFloat64SumObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewInt64UpDownSumObserver calls `BatchObserver.NewInt64UpDownSumObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewInt64UpDownSumObserver(name string, oos ...InstrumentOption) Int64UpDownSumObserver { - if inst, err := bm.batch.NewInt64UpDownSumObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} - -// NewFloat64UpDownSumObserver calls `BatchObserver.NewFloat64UpDownSumObserver` and -// returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) NewFloat64UpDownSumObserver(name string, oos ...InstrumentOption) Float64UpDownSumObserver { - if inst, err := bm.batch.NewFloat64UpDownSumObserver(name, oos...); err != nil { - panic(err) - } else { - return inst - } -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/numberkind_string.go b/vendor/go.opentelemetry.io/otel/api/metric/numberkind_string.go deleted file mode 100644 index e99a8745e4b4..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/numberkind_string.go +++ /dev/null @@ -1,24 +0,0 @@ -// Code generated by "stringer -type=NumberKind"; DO NOT EDIT. - -package metric - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[Int64NumberKind-0] - _ = x[Float64NumberKind-1] -} - -const _NumberKind_name = "Int64NumberKindFloat64NumberKind" - -var _NumberKind_index = [...]uint8{0, 15, 32} - -func (i NumberKind) String() string { - if i < 0 || i >= NumberKind(len(_NumberKind_index)-1) { - return "NumberKind(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _NumberKind_name[_NumberKind_index[i]:_NumberKind_index[i+1]] -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/observer.go b/vendor/go.opentelemetry.io/otel/api/metric/observer.go deleted file mode 100644 index c347da78f155..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/observer.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -// BatchObserver represents an Observer callback that can report -// observations for multiple instruments. -type BatchObserver struct { - meter Meter - runner AsyncBatchRunner -} - -// Int64ValueObserver is a metric that captures a set of int64 values at a -// point in time. -type Int64ValueObserver struct { - asyncInstrument -} - -// Float64ValueObserver is a metric that captures a set of float64 values -// at a point in time. -type Float64ValueObserver struct { - asyncInstrument -} - -// Int64SumObserver is a metric that captures a precomputed sum of -// int64 values at a point in time. -type Int64SumObserver struct { - asyncInstrument -} - -// Float64SumObserver is a metric that captures a precomputed sum of -// float64 values at a point in time. -type Float64SumObserver struct { - asyncInstrument -} - -// Int64UpDownSumObserver is a metric that captures a precomputed sum of -// int64 values at a point in time. -type Int64UpDownSumObserver struct { - asyncInstrument -} - -// Float64UpDownSumObserver is a metric that captures a precomputed sum of -// float64 values at a point in time. -type Float64UpDownSumObserver struct { - asyncInstrument -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (i Int64ValueObserver) Observation(v int64) Observation { - return Observation{ - number: NewInt64Number(v), - instrument: i.instrument, - } -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (f Float64ValueObserver) Observation(v float64) Observation { - return Observation{ - number: NewFloat64Number(v), - instrument: f.instrument, - } -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (i Int64SumObserver) Observation(v int64) Observation { - return Observation{ - number: NewInt64Number(v), - instrument: i.instrument, - } -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (f Float64SumObserver) Observation(v float64) Observation { - return Observation{ - number: NewFloat64Number(v), - instrument: f.instrument, - } -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (i Int64UpDownSumObserver) Observation(v int64) Observation { - return Observation{ - number: NewInt64Number(v), - instrument: i.instrument, - } -} - -// Observation returns an Observation, a BatchObserverFunc -// argument, for an asynchronous integer instrument. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (f Float64UpDownSumObserver) Observation(v float64) Observation { - return Observation{ - number: NewFloat64Number(v), - instrument: f.instrument, - } -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/sync.go b/vendor/go.opentelemetry.io/otel/api/metric/sync.go deleted file mode 100644 index a08a65ba1277..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/sync.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -import ( - "context" - "errors" - - "go.opentelemetry.io/otel/label" -) - -// ErrSDKReturnedNilImpl is returned when a new `MeterImpl` returns nil. -var ErrSDKReturnedNilImpl = errors.New("SDK returned a nil implementation") - -// Measurement is used for reporting a synchronous batch of metric -// values. Instances of this type should be created by synchronous -// instruments (e.g., Int64Counter.Measurement()). -type Measurement struct { - // number needs to be aligned for 64-bit atomic operations. - number Number - instrument SyncImpl -} - -// syncInstrument contains a SyncImpl. -type syncInstrument struct { - instrument SyncImpl -} - -// syncBoundInstrument contains a BoundSyncImpl. -type syncBoundInstrument struct { - boundInstrument BoundSyncImpl -} - -// asyncInstrument contains a AsyncImpl. -type asyncInstrument struct { - instrument AsyncImpl -} - -// SyncImpl returns the instrument that created this measurement. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (m Measurement) SyncImpl() SyncImpl { - return m.instrument -} - -// Number returns a number recorded in this measurement. -func (m Measurement) Number() Number { - return m.number -} - -// AsyncImpl returns the instrument that created this observation. -// This returns an implementation-level object for use by the SDK, -// users should not refer to this. -func (m Observation) AsyncImpl() AsyncImpl { - return m.instrument -} - -// Number returns a number recorded in this observation. -func (m Observation) Number() Number { - return m.number -} - -// AsyncImpl implements AsyncImpl. -func (a asyncInstrument) AsyncImpl() AsyncImpl { - return a.instrument -} - -// SyncImpl returns the implementation object for synchronous instruments. -func (s syncInstrument) SyncImpl() SyncImpl { - return s.instrument -} - -func (s syncInstrument) bind(labels []label.KeyValue) syncBoundInstrument { - return newSyncBoundInstrument(s.instrument.Bind(labels)) -} - -func (s syncInstrument) float64Measurement(value float64) Measurement { - return newMeasurement(s.instrument, NewFloat64Number(value)) -} - -func (s syncInstrument) int64Measurement(value int64) Measurement { - return newMeasurement(s.instrument, NewInt64Number(value)) -} - -func (s syncInstrument) directRecord(ctx context.Context, number Number, labels []label.KeyValue) { - s.instrument.RecordOne(ctx, number, labels) -} - -func (h syncBoundInstrument) directRecord(ctx context.Context, number Number) { - h.boundInstrument.RecordOne(ctx, number) -} - -// Unbind calls SyncImpl.Unbind. -func (h syncBoundInstrument) Unbind() { - h.boundInstrument.Unbind() -} - -// checkNewAsync receives an AsyncImpl and potential -// error, and returns the same types, checking for and ensuring that -// the returned interface is not nil. -func checkNewAsync(instrument AsyncImpl, err error) (asyncInstrument, error) { - if instrument == nil { - if err == nil { - err = ErrSDKReturnedNilImpl - } - instrument = NoopAsync{} - } - return asyncInstrument{ - instrument: instrument, - }, err -} - -// checkNewSync receives an SyncImpl and potential -// error, and returns the same types, checking for and ensuring that -// the returned interface is not nil. -func checkNewSync(instrument SyncImpl, err error) (syncInstrument, error) { - if instrument == nil { - if err == nil { - err = ErrSDKReturnedNilImpl - } - // Note: an alternate behavior would be to synthesize a new name - // or group all duplicately-named instruments of a certain type - // together and use a tag for the original name, e.g., - // name = 'invalid.counter.int64' - // label = 'original-name=duplicate-counter-name' - instrument = NoopSync{} - } - return syncInstrument{ - instrument: instrument, - }, err -} - -func newSyncBoundInstrument(boundInstrument BoundSyncImpl) syncBoundInstrument { - return syncBoundInstrument{ - boundInstrument: boundInstrument, - } -} - -func newMeasurement(instrument SyncImpl, number Number) Measurement { - return Measurement{ - instrument: instrument, - number: number, - } -} - -// wrapInt64CounterInstrument converts a SyncImpl into Int64Counter. -func wrapInt64CounterInstrument(syncInst SyncImpl, err error) (Int64Counter, error) { - common, err := checkNewSync(syncInst, err) - return Int64Counter{syncInstrument: common}, err -} - -// wrapFloat64CounterInstrument converts a SyncImpl into Float64Counter. -func wrapFloat64CounterInstrument(syncInst SyncImpl, err error) (Float64Counter, error) { - common, err := checkNewSync(syncInst, err) - return Float64Counter{syncInstrument: common}, err -} - -// wrapInt64UpDownCounterInstrument converts a SyncImpl into Int64UpDownCounter. -func wrapInt64UpDownCounterInstrument(syncInst SyncImpl, err error) (Int64UpDownCounter, error) { - common, err := checkNewSync(syncInst, err) - return Int64UpDownCounter{syncInstrument: common}, err -} - -// wrapFloat64UpDownCounterInstrument converts a SyncImpl into Float64UpDownCounter. -func wrapFloat64UpDownCounterInstrument(syncInst SyncImpl, err error) (Float64UpDownCounter, error) { - common, err := checkNewSync(syncInst, err) - return Float64UpDownCounter{syncInstrument: common}, err -} - -// wrapInt64ValueRecorderInstrument converts a SyncImpl into Int64ValueRecorder. -func wrapInt64ValueRecorderInstrument(syncInst SyncImpl, err error) (Int64ValueRecorder, error) { - common, err := checkNewSync(syncInst, err) - return Int64ValueRecorder{syncInstrument: common}, err -} - -// wrapFloat64ValueRecorderInstrument converts a SyncImpl into Float64ValueRecorder. -func wrapFloat64ValueRecorderInstrument(syncInst SyncImpl, err error) (Float64ValueRecorder, error) { - common, err := checkNewSync(syncInst, err) - return Float64ValueRecorder{syncInstrument: common}, err -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/updowncounter.go b/vendor/go.opentelemetry.io/otel/api/metric/updowncounter.go deleted file mode 100644 index 10182460aaf2..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/updowncounter.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -import ( - "context" - - "go.opentelemetry.io/otel/label" -) - -// Float64UpDownCounter is a metric instrument that sums floating -// point values. -type Float64UpDownCounter struct { - syncInstrument -} - -// Int64UpDownCounter is a metric instrument that sums integer values. -type Int64UpDownCounter struct { - syncInstrument -} - -// BoundFloat64UpDownCounter is a bound instrument for Float64UpDownCounter. -// -// It inherits the Unbind function from syncBoundInstrument. -type BoundFloat64UpDownCounter struct { - syncBoundInstrument -} - -// BoundInt64UpDownCounter is a boundInstrument for Int64UpDownCounter. -// -// It inherits the Unbind function from syncBoundInstrument. -type BoundInt64UpDownCounter struct { - syncBoundInstrument -} - -// Bind creates a bound instrument for this counter. The labels are -// associated with values recorded via subsequent calls to Record. -func (c Float64UpDownCounter) Bind(labels ...label.KeyValue) (h BoundFloat64UpDownCounter) { - h.syncBoundInstrument = c.bind(labels) - return -} - -// Bind creates a bound instrument for this counter. The labels are -// associated with values recorded via subsequent calls to Record. -func (c Int64UpDownCounter) Bind(labels ...label.KeyValue) (h BoundInt64UpDownCounter) { - h.syncBoundInstrument = c.bind(labels) - return -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Float64UpDownCounter) Measurement(value float64) Measurement { - return c.float64Measurement(value) -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Int64UpDownCounter) Measurement(value int64) Measurement { - return c.int64Measurement(value) -} - -// Add adds the value to the counter's sum. The labels should contain -// the keys and values to be associated with this value. -func (c Float64UpDownCounter) Add(ctx context.Context, value float64, labels ...label.KeyValue) { - c.directRecord(ctx, NewFloat64Number(value), labels) -} - -// Add adds the value to the counter's sum. The labels should contain -// the keys and values to be associated with this value. -func (c Int64UpDownCounter) Add(ctx context.Context, value int64, labels ...label.KeyValue) { - c.directRecord(ctx, NewInt64Number(value), labels) -} - -// Add adds the value to the counter's sum using the labels -// previously bound to this counter via Bind() -func (b BoundFloat64UpDownCounter) Add(ctx context.Context, value float64) { - b.directRecord(ctx, NewFloat64Number(value)) -} - -// Add adds the value to the counter's sum using the labels -// previously bound to this counter via Bind() -func (b BoundInt64UpDownCounter) Add(ctx context.Context, value int64) { - b.directRecord(ctx, NewInt64Number(value)) -} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/valuerecorder.go b/vendor/go.opentelemetry.io/otel/api/metric/valuerecorder.go deleted file mode 100644 index fa7e2d4f8a5b..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/metric/valuerecorder.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -import ( - "context" - - "go.opentelemetry.io/otel/label" -) - -// Float64ValueRecorder is a metric that records float64 values. -type Float64ValueRecorder struct { - syncInstrument -} - -// Int64ValueRecorder is a metric that records int64 values. -type Int64ValueRecorder struct { - syncInstrument -} - -// BoundFloat64ValueRecorder is a bound instrument for Float64ValueRecorder. -// -// It inherits the Unbind function from syncBoundInstrument. -type BoundFloat64ValueRecorder struct { - syncBoundInstrument -} - -// BoundInt64ValueRecorder is a bound instrument for Int64ValueRecorder. -// -// It inherits the Unbind function from syncBoundInstrument. -type BoundInt64ValueRecorder struct { - syncBoundInstrument -} - -// Bind creates a bound instrument for this ValueRecorder. The labels are -// associated with values recorded via subsequent calls to Record. -func (c Float64ValueRecorder) Bind(labels ...label.KeyValue) (h BoundFloat64ValueRecorder) { - h.syncBoundInstrument = c.bind(labels) - return -} - -// Bind creates a bound instrument for this ValueRecorder. The labels are -// associated with values recorded via subsequent calls to Record. -func (c Int64ValueRecorder) Bind(labels ...label.KeyValue) (h BoundInt64ValueRecorder) { - h.syncBoundInstrument = c.bind(labels) - return -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Float64ValueRecorder) Measurement(value float64) Measurement { - return c.float64Measurement(value) -} - -// Measurement creates a Measurement object to use with batch -// recording. -func (c Int64ValueRecorder) Measurement(value int64) Measurement { - return c.int64Measurement(value) -} - -// Record adds a new value to the list of ValueRecorder's records. The -// labels should contain the keys and values to be associated with -// this value. -func (c Float64ValueRecorder) Record(ctx context.Context, value float64, labels ...label.KeyValue) { - c.directRecord(ctx, NewFloat64Number(value), labels) -} - -// Record adds a new value to the ValueRecorder's distribution. The -// labels should contain the keys and values to be associated with -// this value. -func (c Int64ValueRecorder) Record(ctx context.Context, value int64, labels ...label.KeyValue) { - c.directRecord(ctx, NewInt64Number(value), labels) -} - -// Record adds a new value to the ValueRecorder's distribution using the labels -// previously bound to the ValueRecorder via Bind(). -func (b BoundFloat64ValueRecorder) Record(ctx context.Context, value float64) { - b.directRecord(ctx, NewFloat64Number(value)) -} - -// Record adds a new value to the ValueRecorder's distribution using the labels -// previously bound to the ValueRecorder via Bind(). -func (b BoundInt64ValueRecorder) Record(ctx context.Context, value int64) { - b.directRecord(ctx, NewInt64Number(value)) -} diff --git a/vendor/go.opentelemetry.io/otel/api/propagation/propagation.go b/vendor/go.opentelemetry.io/otel/api/propagation/propagation.go deleted file mode 100644 index 8e2d38338bb0..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/propagation/propagation.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package propagation - -import ( - "context" -) - -// HTTPSupplier is an interface that specifies methods to retrieve and -// store a single value for a key to an associated carrier. It is -// implemented by http.Headers. -type HTTPSupplier interface { - // Get method retrieves a single value for a given key. - Get(key string) string - // Set method stores a single value for a given key. Note that - // this should not be appending a value to some array, but - // rather overwrite the old value. - Set(key string, value string) -} - -// HTTPExtractor extracts information from a HTTPSupplier into a -// context. -type HTTPExtractor interface { - // Extract method retrieves encoded information using supplier - // from the associated carrier, decodes it and creates a new - // context containing the decoded information. - // - // Information can be a correlation context or a remote span - // context. In case of span context, the propagator should - // store it in the context using - // trace.ContextWithRemoteSpanContext. In case of correlation - // context, the propagator should use correlation.WithMap to - // store it in the context. - Extract(context.Context, HTTPSupplier) context.Context -} - -// HTTPInjector injects information into a HTTPSupplier. -type HTTPInjector interface { - // Inject method retrieves information from the context, - // encodes it into propagator specific format and then injects - // the encoded information using supplier into an associated - // carrier. - Inject(context.Context, HTTPSupplier) -} - -// Config contains the current set of extractors and injectors. -type Config struct { - httpEx []HTTPExtractor - httpIn []HTTPInjector -} - -// Propagators is the interface to a set of injectors and extractors -// for all supported carrier formats. It can be used to chain multiple -// propagators into a single entity. -type Propagators interface { - // HTTPExtractors returns the configured extractors. - HTTPExtractors() []HTTPExtractor - - // HTTPInjectors returns the configured injectors. - HTTPInjectors() []HTTPInjector -} - -// HTTPPropagator is the interface to inject to and extract from -// HTTPSupplier. -type HTTPPropagator interface { - HTTPInjector - HTTPExtractor - - // GetAllKeys returns the HTTP header names used. - GetAllKeys() []string -} - -// Option support passing configuration parameters to New(). -type Option func(*Config) - -// propagators is the default Propagators implementation. -type propagators struct { - config Config -} - -// New returns a standard Propagators implementation. -func New(options ...Option) Propagators { - config := Config{} - for _, opt := range options { - opt(&config) - } - return &propagators{ - config: config, - } -} - -// WithInjectors appends to the optional injector set. -func WithInjectors(inj ...HTTPInjector) Option { - return func(config *Config) { - config.httpIn = append(config.httpIn, inj...) - } -} - -// WithExtractors appends to the optional extractor set. -func WithExtractors(ext ...HTTPExtractor) Option { - return func(config *Config) { - config.httpEx = append(config.httpEx, ext...) - } -} - -// HTTPExtractors implements Propagators. -func (p *propagators) HTTPExtractors() []HTTPExtractor { - return p.config.httpEx -} - -// HTTPInjectors implements Propagators. -func (p *propagators) HTTPInjectors() []HTTPInjector { - return p.config.httpIn -} - -// ExtractHTTP applies props.HTTPExtractors() to the passed context -// and the supplier and returns the combined result context. -func ExtractHTTP(ctx context.Context, props Propagators, supplier HTTPSupplier) context.Context { - for _, ex := range props.HTTPExtractors() { - ctx = ex.Extract(ctx, supplier) - } - return ctx -} - -// InjectHTTP applies props.HTTPInjectors() to the passed context and -// the supplier. -func InjectHTTP(ctx context.Context, props Propagators, supplier HTTPSupplier) { - for _, in := range props.HTTPInjectors() { - in.Inject(ctx, supplier) - } -} diff --git a/vendor/go.opentelemetry.io/otel/api/trace/api.go b/vendor/go.opentelemetry.io/otel/api/trace/api.go deleted file mode 100644 index 19528d43bda5..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/trace/api.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - "time" - - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/label" -) - -type Provider interface { - // Tracer creates an implementation of the Tracer interface. - // The instrumentationName must be the name of the library providing - // instrumentation. This name may be the same as the instrumented code - // only if that code provides built-in instrumentation. If the - // instrumentationName is empty, then a implementation defined default - // name will be used instead. - Tracer(instrumentationName string, opts ...TracerOption) Tracer -} - -// TODO (MrAlias): unify this API option design: -// https://github.com/open-telemetry/opentelemetry-go/issues/536 - -// TracerConfig contains options for a Tracer. -type TracerConfig struct { - InstrumentationVersion string -} - -// TracerOption configures a TracerConfig option. -type TracerOption func(*TracerConfig) - -// WithInstrumentationVersion sets the instrumentation version for a Tracer. -func WithInstrumentationVersion(version string) TracerOption { - return func(c *TracerConfig) { - c.InstrumentationVersion = version - } -} - -type Tracer interface { - // Start a span. - Start(ctx context.Context, spanName string, opts ...StartOption) (context.Context, Span) -} - -// EndConfig provides options to set properties of span at the time of ending -// the span. -type EndConfig struct { - EndTime time.Time -} - -// EndOption applies changes to EndConfig that sets options when the span is ended. -type EndOption func(*EndConfig) - -// WithEndTime sets the end time of the span to provided time t, when it is ended. -func WithEndTime(t time.Time) EndOption { - return func(c *EndConfig) { - c.EndTime = t - } -} - -// ErrorConfig provides options to set properties of an error event at the time it is recorded. -type ErrorConfig struct { - Timestamp time.Time - StatusCode codes.Code -} - -// ErrorOption applies changes to ErrorConfig that sets options when an error event is recorded. -type ErrorOption func(*ErrorConfig) - -// WithErrorTime sets the time at which the error event should be recorded. -func WithErrorTime(t time.Time) ErrorOption { - return func(c *ErrorConfig) { - c.Timestamp = t - } -} - -// WithErrorStatus indicates the span status that should be set when recording an error event. -func WithErrorStatus(s codes.Code) ErrorOption { - return func(c *ErrorConfig) { - c.StatusCode = s - } -} - -type Span interface { - // Tracer returns tracer used to create this span. Tracer cannot be nil. - Tracer() Tracer - - // End completes the span. No updates are allowed to span after it - // ends. The only exception is setting status of the span. - End(options ...EndOption) - - // AddEvent adds an event to the span. - AddEvent(ctx context.Context, name string, attrs ...label.KeyValue) - // AddEventWithTimestamp adds an event with a custom timestamp - // to the span. - AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...label.KeyValue) - - // IsRecording returns true if the span is active and recording events is enabled. - IsRecording() bool - - // RecordError records an error as a span event. - RecordError(ctx context.Context, err error, opts ...ErrorOption) - - // SpanContext returns span context of the span. Returned SpanContext is usable - // even after the span ends. - SpanContext() SpanContext - - // SetStatus sets the status of the span in the form of a code - // and a message. SetStatus overrides the value of previous - // calls to SetStatus on the Span. - // - // The default span status is OK, so it is not necessary to - // explicitly set an OK status on successful Spans unless it - // is to add an OK message or to override a previous status on the Span. - SetStatus(codes.Code, string) - - // SetName sets the name of the span. - SetName(name string) - - // Set span attributes - SetAttributes(...label.KeyValue) - - // Set singular span attribute, with type inference. - SetAttribute(string, interface{}) -} - -// StartOption applies changes to StartConfig that sets options at span start time. -type StartOption func(*StartConfig) - -// StartConfig provides options to set properties of span at the time of starting -// a new span. -type StartConfig struct { - Attributes []label.KeyValue - StartTime time.Time - Links []Link - Record bool - NewRoot bool - SpanKind SpanKind -} - -// Link is used to establish relationship between two spans within the same Trace or -// across different Traces. Few examples of Link usage. -// 1. Batch Processing: A batch of elements may contain elements associated with one -// or more traces/spans. Since there can only be one parent SpanContext, Link is -// used to keep reference to SpanContext of all elements in the batch. -// 2. Public Endpoint: A SpanContext in incoming client request on a public endpoint -// is untrusted from service provider perspective. In such case it is advisable to -// start a new trace with appropriate sampling decision. -// However, it is desirable to associate incoming SpanContext to new trace initiated -// on service provider side so two traces (from Client and from Service Provider) can -// be correlated. -type Link struct { - SpanContext - Attributes []label.KeyValue -} - -// SpanKind represents the role of a Span inside a Trace. Often, this defines how a Span -// will be processed and visualized by various backends. -type SpanKind int - -const ( - // As a convenience, these match the proto definition, see - // opentelemetry/proto/trace/v1/trace.proto - // - // The unspecified value is not a valid `SpanKind`. Use - // `ValidateSpanKind()` to coerce a span kind to a valid - // value. - SpanKindUnspecified SpanKind = 0 - SpanKindInternal SpanKind = 1 - SpanKindServer SpanKind = 2 - SpanKindClient SpanKind = 3 - SpanKindProducer SpanKind = 4 - SpanKindConsumer SpanKind = 5 -) - -// ValidateSpanKind returns a valid span kind value. This will coerce -// invalid values into the default value, SpanKindInternal. -func ValidateSpanKind(spanKind SpanKind) SpanKind { - switch spanKind { - case SpanKindInternal, - SpanKindServer, - SpanKindClient, - SpanKindProducer, - SpanKindConsumer: - // valid - return spanKind - default: - return SpanKindInternal - } -} - -// String returns the specified name of the SpanKind in lower-case. -func (sk SpanKind) String() string { - switch sk { - case SpanKindInternal: - return "internal" - case SpanKindServer: - return "server" - case SpanKindClient: - return "client" - case SpanKindProducer: - return "producer" - case SpanKindConsumer: - return "consumer" - default: - return "unspecified" - } -} - -// WithStartTime sets the start time of the span to provided time t, when it is started. -// In absence of this option, wall clock time is used as start time. -// This option is typically used when starting of the span is delayed. -func WithStartTime(t time.Time) StartOption { - return func(c *StartConfig) { - c.StartTime = t - } -} - -// WithAttributes sets attributes to span. These attributes provides additional -// data about the span. -// Multiple `WithAttributes` options appends the attributes preserving the order. -func WithAttributes(attrs ...label.KeyValue) StartOption { - return func(c *StartConfig) { - c.Attributes = append(c.Attributes, attrs...) - } -} - -// WithRecord specifies that the span should be recorded. -// Note that the implementation may still override this preference, -// e.g., if the span is a child in an unsampled trace. -func WithRecord() StartOption { - return func(c *StartConfig) { - c.Record = true - } -} - -// WithNewRoot specifies that the current span or remote span context -// in context passed to `Start` should be ignored when deciding about -// a parent, which effectively means creating a span with new trace -// ID. The current span and the remote span context may be added as -// links to the span by the implementation. -func WithNewRoot() StartOption { - return func(c *StartConfig) { - c.NewRoot = true - } -} - -// LinkedTo allows instantiating a Span with initial Links. -func LinkedTo(sc SpanContext, attrs ...label.KeyValue) StartOption { - return func(c *StartConfig) { - c.Links = append(c.Links, Link{sc, attrs}) - } -} - -// WithSpanKind specifies the role a Span on a Trace. -func WithSpanKind(sk SpanKind) StartOption { - return func(c *StartConfig) { - c.SpanKind = sk - } -} diff --git a/vendor/go.opentelemetry.io/otel/api/trace/b3_propagator.go b/vendor/go.opentelemetry.io/otel/api/trace/b3_propagator.go deleted file mode 100644 index 4627618f70bf..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/trace/b3_propagator.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - "errors" - "strings" - - "go.opentelemetry.io/otel/api/propagation" -) - -const ( - // Default B3 Header names. - b3ContextHeader = "b3" - b3DebugFlagHeader = "x-b3-flags" - b3TraceIDHeader = "x-b3-traceid" - b3SpanIDHeader = "x-b3-spanid" - b3SampledHeader = "x-b3-sampled" - b3ParentSpanIDHeader = "x-b3-parentspanid" - - b3TraceIDPadding = "0000000000000000" - - // B3 Single Header encoding widths. - separatorWidth = 1 // Single "-" character. - samplingWidth = 1 // Single hex character. - traceID64BitsWidth = 64 / 4 // 16 hex character Trace ID. - traceID128BitsWidth = 128 / 4 // 32 hex character Trace ID. - spanIDWidth = 16 // 16 hex character ID. - parentSpanIDWidth = 16 // 16 hex character ID. -) - -var ( - empty = EmptySpanContext() - - errInvalidSampledByte = errors.New("invalid B3 Sampled found") - errInvalidSampledHeader = errors.New("invalid B3 Sampled header found") - errInvalidTraceIDHeader = errors.New("invalid B3 TraceID header found") - errInvalidSpanIDHeader = errors.New("invalid B3 SpanID header found") - errInvalidParentSpanIDHeader = errors.New("invalid B3 ParentSpanID header found") - errInvalidScope = errors.New("require either both TraceID and SpanID or none") - errInvalidScopeParent = errors.New("ParentSpanID requires both TraceID and SpanID to be available") - errInvalidScopeParentSingle = errors.New("ParentSpanID requires TraceID, SpanID and Sampled to be available") - errEmptyContext = errors.New("empty request context") - errInvalidTraceIDValue = errors.New("invalid B3 TraceID value found") - errInvalidSpanIDValue = errors.New("invalid B3 SpanID value found") - errInvalidParentSpanIDValue = errors.New("invalid B3 ParentSpanID value found") -) - -// B3Encoding is a bitmask representation of the B3 encoding type. -type B3Encoding uint8 - -// supports returns if e has o bit(s) set. -func (e B3Encoding) supports(o B3Encoding) bool { - return e&o == o -} - -const ( - // B3MultipleHeader is a B3 encoding that uses multiple headers to - // transmit tracing information all prefixed with `x-b3-`. - B3MultipleHeader B3Encoding = 1 << iota - // B3SingleHeader is a B3 encoding that uses a single header named `b3` - // to transmit tracing information. - B3SingleHeader - // B3Unspecified is an unspecified B3 encoding. - B3Unspecified B3Encoding = 0 -) - -// B3 propagator serializes SpanContext to/from B3 Headers. -// This propagator supports both versions of B3 headers, -// 1. Single Header: -// b3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId} -// 2. Multiple Headers: -// x-b3-traceid: {TraceId} -// x-b3-parentspanid: {ParentSpanId} -// x-b3-spanid: {SpanId} -// x-b3-sampled: {SamplingState} -// x-b3-flags: {DebugFlag} -type B3 struct { - // InjectEncoding are the B3 encodings used when injecting trace - // information. If no encoding is specified (i.e. `B3Unspecified`) - // `B3MultipleHeader` will be used as the default. - InjectEncoding B3Encoding -} - -var _ propagation.HTTPPropagator = B3{} - -// Inject injects a context into the supplier as B3 headers. -// The parent span ID is omitted because it is not tracked in the -// SpanContext. -func (b3 B3) Inject(ctx context.Context, supplier propagation.HTTPSupplier) { - sc := SpanFromContext(ctx).SpanContext() - - if b3.InjectEncoding.supports(B3SingleHeader) { - header := []string{} - if sc.TraceID.IsValid() && sc.SpanID.IsValid() { - header = append(header, sc.TraceID.String(), sc.SpanID.String()) - } - - if sc.isDebug() { - header = append(header, "d") - } else if !sc.isDeferred() { - if sc.IsSampled() { - header = append(header, "1") - } else { - header = append(header, "0") - } - } - - supplier.Set(b3ContextHeader, strings.Join(header, "-")) - } - - if b3.InjectEncoding.supports(B3MultipleHeader) || b3.InjectEncoding == B3Unspecified { - if sc.TraceID.IsValid() && sc.SpanID.IsValid() { - supplier.Set(b3TraceIDHeader, sc.TraceID.String()) - supplier.Set(b3SpanIDHeader, sc.SpanID.String()) - } - - if sc.isDebug() { - // Since Debug implies deferred, don't also send "X-B3-Sampled". - supplier.Set(b3DebugFlagHeader, "1") - } else if !sc.isDeferred() { - if sc.IsSampled() { - supplier.Set(b3SampledHeader, "1") - } else { - supplier.Set(b3SampledHeader, "0") - } - } - } -} - -// Extract extracts a context from the supplier if it contains B3 headers. -func (b3 B3) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context { - var ( - sc SpanContext - err error - ) - - // Default to Single Header if a valid value exists. - if h := supplier.Get(b3ContextHeader); h != "" { - sc, err = extractSingle(h) - if err == nil && sc.IsValid() { - return ContextWithRemoteSpanContext(ctx, sc) - } - // The Single Header value was invalid, fallback to Multiple Header. - } - - var ( - traceID = supplier.Get(b3TraceIDHeader) - spanID = supplier.Get(b3SpanIDHeader) - parentSpanID = supplier.Get(b3ParentSpanIDHeader) - sampled = supplier.Get(b3SampledHeader) - debugFlag = supplier.Get(b3DebugFlagHeader) - ) - sc, err = extractMultiple(traceID, spanID, parentSpanID, sampled, debugFlag) - if err != nil || !sc.IsValid() { - return ctx - } - return ContextWithRemoteSpanContext(ctx, sc) -} - -func (b3 B3) GetAllKeys() []string { - header := []string{} - if b3.InjectEncoding.supports(B3SingleHeader) { - header = append(header, b3ContextHeader) - } - if b3.InjectEncoding.supports(B3MultipleHeader) || b3.InjectEncoding == B3Unspecified { - header = append(header, b3TraceIDHeader, b3SpanIDHeader, b3SampledHeader, b3DebugFlagHeader) - } - return header -} - -// extractMultiple reconstructs a SpanContext from header values based on B3 -// Multiple header. It is based on the implementation found here: -// https://github.com/openzipkin/zipkin-go/blob/v0.2.2/propagation/b3/spancontext.go -// and adapted to support a SpanContext. -func extractMultiple(traceID, spanID, parentSpanID, sampled, flags string) (SpanContext, error) { - var ( - err error - requiredCount int - sc = SpanContext{} - ) - - // correct values for an existing sampled header are "0" and "1". - // For legacy support and being lenient to other tracing implementations we - // allow "true" and "false" as inputs for interop purposes. - switch strings.ToLower(sampled) { - case "0", "false": - // Zero value for TraceFlags sample bit is unset. - case "1", "true": - sc.TraceFlags = FlagsSampled - case "": - sc.TraceFlags = FlagsDeferred - default: - return empty, errInvalidSampledHeader - } - - // The only accepted value for Flags is "1". This will set Debug to - // true. All other values and omission of header will be ignored. - if flags == "1" { - sc.TraceFlags |= FlagsDebug - } - - if traceID != "" { - requiredCount++ - id := traceID - if len(traceID) == 16 { - // Pad 64-bit trace IDs. - id = b3TraceIDPadding + traceID - } - if sc.TraceID, err = IDFromHex(id); err != nil { - return empty, errInvalidTraceIDHeader - } - } - - if spanID != "" { - requiredCount++ - if sc.SpanID, err = SpanIDFromHex(spanID); err != nil { - return empty, errInvalidSpanIDHeader - } - } - - if requiredCount != 0 && requiredCount != 2 { - return empty, errInvalidScope - } - - if parentSpanID != "" { - if requiredCount == 0 { - return empty, errInvalidScopeParent - } - // Validate parent span ID but we do not use it so do not save it. - if _, err = SpanIDFromHex(parentSpanID); err != nil { - return empty, errInvalidParentSpanIDHeader - } - } - - return sc, nil -} - -// extractSingle reconstructs a SpanContext from contextHeader based on a B3 -// Single header. It is based on the implementation found here: -// https://github.com/openzipkin/zipkin-go/blob/v0.2.2/propagation/b3/spancontext.go -// and adapted to support a SpanContext. -func extractSingle(contextHeader string) (SpanContext, error) { - if contextHeader == "" { - return empty, errEmptyContext - } - - var ( - sc = SpanContext{} - sampling string - ) - - headerLen := len(contextHeader) - - if headerLen == samplingWidth { - sampling = contextHeader - } else if headerLen == traceID64BitsWidth || headerLen == traceID128BitsWidth { - // Trace ID by itself is invalid. - return empty, errInvalidScope - } else if headerLen >= traceID64BitsWidth+spanIDWidth+separatorWidth { - pos := 0 - var traceID string - if string(contextHeader[traceID64BitsWidth]) == "-" { - // traceID must be 64 bits - pos += traceID64BitsWidth // {traceID} - traceID = b3TraceIDPadding + string(contextHeader[0:pos]) - } else if string(contextHeader[32]) == "-" { - // traceID must be 128 bits - pos += traceID128BitsWidth // {traceID} - traceID = string(contextHeader[0:pos]) - } else { - return empty, errInvalidTraceIDValue - } - var err error - sc.TraceID, err = IDFromHex(traceID) - if err != nil { - return empty, errInvalidTraceIDValue - } - pos += separatorWidth // {traceID}- - - sc.SpanID, err = SpanIDFromHex(contextHeader[pos : pos+spanIDWidth]) - if err != nil { - return empty, errInvalidSpanIDValue - } - pos += spanIDWidth // {traceID}-{spanID} - - if headerLen > pos { - if headerLen == pos+separatorWidth { - // {traceID}-{spanID}- is invalid. - return empty, errInvalidSampledByte - } - pos += separatorWidth // {traceID}-{spanID}- - - if headerLen == pos+samplingWidth { - sampling = string(contextHeader[pos]) - } else if headerLen == pos+parentSpanIDWidth { - // {traceID}-{spanID}-{parentSpanID} is invalid. - return empty, errInvalidScopeParentSingle - } else if headerLen == pos+samplingWidth+separatorWidth+parentSpanIDWidth { - sampling = string(contextHeader[pos]) - pos += samplingWidth + separatorWidth // {traceID}-{spanID}-{sampling}- - - // Validate parent span ID but we do not use it so do not - // save it. - _, err = SpanIDFromHex(contextHeader[pos:]) - if err != nil { - return empty, errInvalidParentSpanIDValue - } - } else { - return empty, errInvalidParentSpanIDValue - } - } - } else { - return empty, errInvalidTraceIDValue - } - switch sampling { - case "": - sc.TraceFlags = FlagsDeferred - case "d": - sc.TraceFlags = FlagsDebug - case "1": - sc.TraceFlags = FlagsSampled - case "0": - // Zero value for TraceFlags sample bit is unset. - default: - return empty, errInvalidSampledByte - } - - return sc, nil -} diff --git a/vendor/go.opentelemetry.io/otel/api/trace/context.go b/vendor/go.opentelemetry.io/otel/api/trace/context.go deleted file mode 100644 index 489e3c12042c..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/trace/context.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" -) - -type traceContextKeyType int - -const ( - currentSpanKey traceContextKeyType = iota - remoteContextKey -) - -// ContextWithSpan creates a new context with a current span set to -// the passed span. -func ContextWithSpan(ctx context.Context, span Span) context.Context { - return context.WithValue(ctx, currentSpanKey, span) -} - -// SpanFromContext returns the current span stored in the context. -func SpanFromContext(ctx context.Context) Span { - if span, has := ctx.Value(currentSpanKey).(Span); has { - return span - } - return NoopSpan{} -} - -// ContextWithRemoteSpanContext creates a new context with a remote -// span context set to the passed span context. -func ContextWithRemoteSpanContext(ctx context.Context, sc SpanContext) context.Context { - return context.WithValue(ctx, remoteContextKey, sc) -} - -// RemoteSpanContextFromContext returns the remote span context stored -// in the context. -func RemoteSpanContextFromContext(ctx context.Context) SpanContext { - if sc, ok := ctx.Value(remoteContextKey).(SpanContext); ok { - return sc - } - return EmptySpanContext() -} diff --git a/vendor/go.opentelemetry.io/otel/api/trace/doc.go b/vendor/go.opentelemetry.io/otel/api/trace/doc.go deleted file mode 100644 index 56c13f049469..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/trace/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace // import "go.opentelemetry.io/otel/api/trace" diff --git a/vendor/go.opentelemetry.io/otel/api/trace/noop_span.go b/vendor/go.opentelemetry.io/otel/api/trace/noop_span.go deleted file mode 100644 index 27f0d319f3dd..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/trace/noop_span.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - "time" - - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/label" -) - -type NoopSpan struct { -} - -var _ Span = (*NoopSpan)(nil) - -// SpanContext returns an invalid span context. -func (NoopSpan) SpanContext() SpanContext { - return EmptySpanContext() -} - -// IsRecording always returns false for NoopSpan. -func (NoopSpan) IsRecording() bool { - return false -} - -// SetStatus does nothing. -func (NoopSpan) SetStatus(status codes.Code, msg string) { -} - -// SetError does nothing. -func (NoopSpan) SetError(v bool) { -} - -// SetAttributes does nothing. -func (NoopSpan) SetAttributes(attributes ...label.KeyValue) { -} - -// SetAttribute does nothing. -func (NoopSpan) SetAttribute(k string, v interface{}) { -} - -// End does nothing. -func (NoopSpan) End(options ...EndOption) { -} - -// RecordError does nothing. -func (NoopSpan) RecordError(ctx context.Context, err error, opts ...ErrorOption) { -} - -// Tracer returns noop implementation of Tracer. -func (NoopSpan) Tracer() Tracer { - return NoopTracer{} -} - -// AddEvent does nothing. -func (NoopSpan) AddEvent(ctx context.Context, name string, attrs ...label.KeyValue) { -} - -// AddEventWithTimestamp does nothing. -func (NoopSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...label.KeyValue) { -} - -// SetName does nothing. -func (NoopSpan) SetName(name string) { -} diff --git a/vendor/go.opentelemetry.io/otel/api/trace/span_context.go b/vendor/go.opentelemetry.io/otel/api/trace/span_context.go deleted file mode 100644 index abce3f76a655..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/trace/span_context.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "bytes" - "encoding/hex" - "encoding/json" -) - -const ( - // FlagsSampled is a bitmask with the sampled bit set. A SpanContext - // with the sampling bit set means the span is sampled. - FlagsSampled = byte(0x01) - // FlagsDeferred is a bitmask with the deferred bit set. A SpanContext - // with the deferred bit set means the sampling decision has been - // defered to the receiver. - FlagsDeferred = byte(0x02) - // FlagsDebug is a bitmask with the debug bit set. - FlagsDebug = byte(0x04) - - ErrInvalidHexID errorConst = "trace-id and span-id can only contain [0-9a-f] characters, all lowercase" - - ErrInvalidTraceIDLength errorConst = "hex encoded trace-id must have length equals to 32" - ErrNilTraceID errorConst = "trace-id can't be all zero" - - ErrInvalidSpanIDLength errorConst = "hex encoded span-id must have length equals to 16" - ErrNilSpanID errorConst = "span-id can't be all zero" -) - -type errorConst string - -func (e errorConst) Error() string { - return string(e) -} - -// ID is a unique identity of a trace. -type ID [16]byte - -var nilTraceID ID -var _ json.Marshaler = nilTraceID - -// IsValid checks whether the trace ID is valid. A valid trace ID does -// not consist of zeros only. -func (t ID) IsValid() bool { - return !bytes.Equal(t[:], nilTraceID[:]) -} - -// MarshalJSON implements a custom marshal function to encode TraceID -// as a hex string. -func (t ID) MarshalJSON() ([]byte, error) { - return json.Marshal(t.String()) -} - -// String returns the hex string representation form of a TraceID -func (t ID) String() string { - return hex.EncodeToString(t[:]) -} - -// SpanID is a unique identify of a span in a trace. -type SpanID [8]byte - -var nilSpanID SpanID -var _ json.Marshaler = nilSpanID - -// IsValid checks whether the span ID is valid. A valid span ID does -// not consist of zeros only. -func (s SpanID) IsValid() bool { - return !bytes.Equal(s[:], nilSpanID[:]) -} - -// MarshalJSON implements a custom marshal function to encode SpanID -// as a hex string. -func (s SpanID) MarshalJSON() ([]byte, error) { - return json.Marshal(s.String()) -} - -// String returns the hex string representation form of a SpanID -func (s SpanID) String() string { - return hex.EncodeToString(s[:]) -} - -// IDFromHex returns a TraceID from a hex string if it is compliant -// with the w3c trace-context specification. -// See more at https://www.w3.org/TR/trace-context/#trace-id -func IDFromHex(h string) (ID, error) { - t := ID{} - if len(h) != 32 { - return t, ErrInvalidTraceIDLength - } - - if err := decodeHex(h, t[:]); err != nil { - return t, err - } - - if !t.IsValid() { - return t, ErrNilTraceID - } - return t, nil -} - -// SpanIDFromHex returns a SpanID from a hex string if it is compliant -// with the w3c trace-context specification. -// See more at https://www.w3.org/TR/trace-context/#parent-id -func SpanIDFromHex(h string) (SpanID, error) { - s := SpanID{} - if len(h) != 16 { - return s, ErrInvalidSpanIDLength - } - - if err := decodeHex(h, s[:]); err != nil { - return s, err - } - - if !s.IsValid() { - return s, ErrNilSpanID - } - return s, nil -} - -func decodeHex(h string, b []byte) error { - for _, r := range h { - switch { - case 'a' <= r && r <= 'f': - continue - case '0' <= r && r <= '9': - continue - default: - return ErrInvalidHexID - } - } - - decoded, err := hex.DecodeString(h) - if err != nil { - return err - } - - copy(b, decoded) - return nil -} - -// SpanContext contains basic information about the span - its trace -// ID, span ID and trace flags. -type SpanContext struct { - TraceID ID - SpanID SpanID - TraceFlags byte -} - -// EmptySpanContext is meant for internal use to return invalid span -// context during error conditions. -func EmptySpanContext() SpanContext { - return SpanContext{} -} - -// IsValid checks if the span context is valid. A valid span context -// has a valid trace ID and a valid span ID. -func (sc SpanContext) IsValid() bool { - return sc.HasTraceID() && sc.HasSpanID() -} - -// HasTraceID checks if the span context has a valid trace ID. -func (sc SpanContext) HasTraceID() bool { - return sc.TraceID.IsValid() -} - -// HasSpanID checks if the span context has a valid span ID. -func (sc SpanContext) HasSpanID() bool { - return sc.SpanID.IsValid() -} - -// isDeferred returns if the deferred bit is set in the trace flags. -func (sc SpanContext) isDeferred() bool { - return sc.TraceFlags&FlagsDeferred == FlagsDeferred -} - -// isDebug returns if the debug bit is set in the trace flags. -func (sc SpanContext) isDebug() bool { - return sc.TraceFlags&FlagsDebug == FlagsDebug -} - -// IsSampled returns if the sampling bit is set in the trace flags. -func (sc SpanContext) IsSampled() bool { - return sc.TraceFlags&FlagsSampled == FlagsSampled -} diff --git a/vendor/go.opentelemetry.io/otel/api/trace/trace_context_propagator.go b/vendor/go.opentelemetry.io/otel/api/trace/trace_context_propagator.go deleted file mode 100644 index 5413106f4403..000000000000 --- a/vendor/go.opentelemetry.io/otel/api/trace/trace_context_propagator.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - "encoding/hex" - "fmt" - "regexp" - - "go.opentelemetry.io/otel/api/propagation" -) - -const ( - supportedVersion = 0 - maxVersion = 254 - traceparentHeader = "traceparent" - tracestateHeader = "tracestate" -) - -type traceContextPropagatorKeyType uint - -const ( - tracestateKey traceContextPropagatorKeyType = 0 -) - -// TraceContext propagates SpanContext in W3C TraceContext format. -//nolint:golint -type TraceContext struct{} - -var _ propagation.HTTPPropagator = TraceContext{} -var traceCtxRegExp = regexp.MustCompile("^(?P[0-9a-f]{2})-(?P[a-f0-9]{32})-(?P[a-f0-9]{16})-(?P[a-f0-9]{2})(?:-.*)?$") - -// DefaultHTTPPropagator returns the default trace HTTP propagator. -func DefaultHTTPPropagator() propagation.HTTPPropagator { - return TraceContext{} -} - -func (TraceContext) Inject(ctx context.Context, supplier propagation.HTTPSupplier) { - tracestate := ctx.Value(tracestateKey) - if state, ok := tracestate.(string); tracestate != nil && ok { - supplier.Set(tracestateHeader, state) - } - - sc := SpanFromContext(ctx).SpanContext() - if !sc.IsValid() { - return - } - h := fmt.Sprintf("%.2x-%s-%s-%.2x", - supportedVersion, - sc.TraceID, - sc.SpanID, - sc.TraceFlags&FlagsSampled) - supplier.Set(traceparentHeader, h) -} - -func (tc TraceContext) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context { - state := supplier.Get(tracestateHeader) - if state != "" { - ctx = context.WithValue(ctx, tracestateKey, state) - } - - sc := tc.extract(supplier) - if !sc.IsValid() { - return ctx - } - return ContextWithRemoteSpanContext(ctx, sc) -} - -func (TraceContext) extract(supplier propagation.HTTPSupplier) SpanContext { - h := supplier.Get(traceparentHeader) - if h == "" { - return EmptySpanContext() - } - - matches := traceCtxRegExp.FindStringSubmatch(h) - - if len(matches) == 0 { - return EmptySpanContext() - } - - if len(matches) < 5 { // four subgroups plus the overall match - return EmptySpanContext() - } - - if len(matches[1]) != 2 { - return EmptySpanContext() - } - ver, err := hex.DecodeString(matches[1]) - if err != nil { - return EmptySpanContext() - } - version := int(ver[0]) - if version > maxVersion { - return EmptySpanContext() - } - - if version == 0 && len(matches) != 5 { // four subgroups plus the overall match - return EmptySpanContext() - } - - if len(matches[2]) != 32 { - return EmptySpanContext() - } - - var sc SpanContext - - sc.TraceID, err = IDFromHex(matches[2][:32]) - if err != nil { - return EmptySpanContext() - } - - if len(matches[3]) != 16 { - return EmptySpanContext() - } - sc.SpanID, err = SpanIDFromHex(matches[3]) - if err != nil { - return EmptySpanContext() - } - - if len(matches[4]) != 2 { - return EmptySpanContext() - } - opts, err := hex.DecodeString(matches[4]) - if err != nil || len(opts) < 1 || (version == 0 && opts[0] > 2) { - return EmptySpanContext() - } - // Clear all flags other than the trace-context supported sampling bit. - sc.TraceFlags = opts[0] & FlagsSampled - - if !sc.IsValid() { - return EmptySpanContext() - } - - return sc -} - -func (TraceContext) GetAllKeys() []string { - return []string{traceparentHeader, tracestateHeader} -} diff --git a/vendor/go.opentelemetry.io/otel/api/trace/noop_trace_provider.go b/vendor/go.opentelemetry.io/otel/attribute/doc.go similarity index 63% rename from vendor/go.opentelemetry.io/otel/api/trace/noop_trace_provider.go rename to vendor/go.opentelemetry.io/otel/attribute/doc.go index 6a5f1a285ef4..44bc32c9e072 100644 --- a/vendor/go.opentelemetry.io/otel/api/trace/noop_trace_provider.go +++ b/vendor/go.opentelemetry.io/otel/attribute/doc.go @@ -12,13 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -package trace - -type NoopProvider struct{} - -var _ Provider = NoopProvider{} - -// Tracer returns noop implementation of Tracer. -func (p NoopProvider) Tracer(_ string, _ ...TracerOption) Tracer { - return NoopTracer{} -} +// package attribute provides key and value attributes. +// +// This package is currently in a pre-GA phase. Backwards incompatible changes +// may be introduced in subsequent minor version releases as we work to track +// the evolving OpenTelemetry specification and user feedback. +package attribute // import "go.opentelemetry.io/otel/attribute" diff --git a/vendor/go.opentelemetry.io/otel/label/encoder.go b/vendor/go.opentelemetry.io/otel/attribute/encoder.go similarity index 97% rename from vendor/go.opentelemetry.io/otel/label/encoder.go rename to vendor/go.opentelemetry.io/otel/attribute/encoder.go index 17e6d2dfb250..8b940f78dc4a 100644 --- a/vendor/go.opentelemetry.io/otel/label/encoder.go +++ b/vendor/go.opentelemetry.io/otel/attribute/encoder.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package label +package attribute // import "go.opentelemetry.io/otel/attribute" import ( "bytes" @@ -28,8 +28,8 @@ type ( Encoder interface { // Encode returns the serialized encoding of the label // set using its Iterator. This result may be cached - // by a label.Set. - Encode(Iterator) string + // by a attribute.Set. + Encode(iterator Iterator) string // ID returns a value that is unique for each class of // label encoder. Label encoders allocate these using diff --git a/vendor/go.opentelemetry.io/otel/label/iterator.go b/vendor/go.opentelemetry.io/otel/attribute/iterator.go similarity index 90% rename from vendor/go.opentelemetry.io/otel/label/iterator.go rename to vendor/go.opentelemetry.io/otel/attribute/iterator.go index 9e72239986c1..e03aabb62bd3 100644 --- a/vendor/go.opentelemetry.io/otel/label/iterator.go +++ b/vendor/go.opentelemetry.io/otel/attribute/iterator.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package label +package attribute // import "go.opentelemetry.io/otel/attribute" // Iterator allows iterating over the set of labels in order, // sorted by key. @@ -24,7 +24,7 @@ type Iterator struct { // MergeIterator supports iterating over two sets of labels while // eliminating duplicate values from the combined set. The first // iterator value takes precedence. -type MergeItererator struct { +type MergeIterator struct { one oneIterator two oneIterator current KeyValue @@ -55,7 +55,7 @@ func (i *Iterator) Attribute() KeyValue { return i.Label() } -// IndexedLabel returns current index and label. Must be called only +// IndexedLabel returns current index and attribute. Must be called only // after Next returns true. func (i *Iterator) IndexedLabel() (int, KeyValue) { return i.idx, i.Label() @@ -84,8 +84,8 @@ func (i *Iterator) ToSlice() []KeyValue { // NewMergeIterator returns a MergeIterator for merging two label sets // Duplicates are resolved by taking the value from the first set. -func NewMergeIterator(s1, s2 *Set) MergeItererator { - mi := MergeItererator{ +func NewMergeIterator(s1, s2 *Set) MergeIterator { + mi := MergeIterator{ one: makeOne(s1.Iter()), two: makeOne(s2.Iter()), } @@ -107,7 +107,7 @@ func (oi *oneIterator) advance() { } // Next returns true if there is another label available. -func (m *MergeItererator) Next() bool { +func (m *MergeIterator) Next() bool { if m.one.done && m.two.done { return false } @@ -138,6 +138,6 @@ func (m *MergeItererator) Next() bool { } // Label returns the current value after Next() returns true. -func (m *MergeItererator) Label() KeyValue { +func (m *MergeIterator) Label() KeyValue { return m.current } diff --git a/vendor/go.opentelemetry.io/otel/label/key.go b/vendor/go.opentelemetry.io/otel/attribute/key.go similarity index 58% rename from vendor/go.opentelemetry.io/otel/label/key.go rename to vendor/go.opentelemetry.io/otel/attribute/key.go index 7d7237809902..492c438a9f54 100644 --- a/vendor/go.opentelemetry.io/otel/label/key.go +++ b/vendor/go.opentelemetry.io/otel/attribute/key.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package label +package attribute // import "go.opentelemetry.io/otel/attribute" // Key represents the key part in key-value pairs. It's a string. The // allowed character set in the key depends on the use of the key. @@ -44,19 +44,6 @@ func (k Key) Int64(v int64) KeyValue { } } -// Uint64 creates a KeyValue instance with a UINT64 Value. -// -// If creating both key and a uint64 value at the same time, then -// instead of calling Key(name).Uint64(value) consider using a -// convenience function provided by the api/key package - -// key.Uint64(name, value). -func (k Key) Uint64(v uint64) KeyValue { - return KeyValue{ - Key: k, - Value: Uint64Value(v), - } -} - // Float64 creates a KeyValue instance with a FLOAT64 Value. // // If creating both key and a float64 value at the same time, then @@ -70,45 +57,6 @@ func (k Key) Float64(v float64) KeyValue { } } -// Int32 creates a KeyValue instance with an INT32 Value. -// -// If creating both key and an int32 value at the same time, then -// instead of calling Key(name).Int32(value) consider using a -// convenience function provided by the api/key package - -// key.Int32(name, value). -func (k Key) Int32(v int32) KeyValue { - return KeyValue{ - Key: k, - Value: Int32Value(v), - } -} - -// Uint32 creates a KeyValue instance with a UINT32 Value. -// -// If creating both key and a uint32 value at the same time, then -// instead of calling Key(name).Uint32(value) consider using a -// convenience function provided by the api/key package - -// key.Uint32(name, value). -func (k Key) Uint32(v uint32) KeyValue { - return KeyValue{ - Key: k, - Value: Uint32Value(v), - } -} - -// Float32 creates a KeyValue instance with a FLOAT32 Value. -// -// If creating both key and a float32 value at the same time, then -// instead of calling Key(name).Float32(value) consider using a -// convenience function provided by the api/key package - -// key.Float32(name, value). -func (k Key) Float32(v float32) KeyValue { - return KeyValue{ - Key: k, - Value: Float32Value(v), - } -} - // String creates a KeyValue instance with a STRING Value. // // If creating both key and a string value at the same time, then @@ -122,8 +70,7 @@ func (k Key) String(v string) KeyValue { } } -// Int creates a KeyValue instance with either an INT32 or an INT64 -// Value, depending on whether the int type is 32 or 64 bits wide. +// Int creates a KeyValue instance with an INT64 Value. // // If creating both key and an int value at the same time, then // instead of calling Key(name).Int(value) consider using a @@ -136,20 +83,6 @@ func (k Key) Int(v int) KeyValue { } } -// Uint creates a KeyValue instance with either a UINT32 or a UINT64 -// Value, depending on whether the uint type is 32 or 64 bits wide. -// -// If creating both key and a uint value at the same time, then -// instead of calling Key(name).Uint(value) consider using a -// convenience function provided by the api/key package - -// key.Uint(name, value). -func (k Key) Uint(v uint) KeyValue { - return KeyValue{ - Key: k, - Value: UintValue(v), - } -} - // Defined returns true for non-empty keys. func (k Key) Defined() bool { return len(k) != 0 diff --git a/vendor/go.opentelemetry.io/otel/label/kv.go b/vendor/go.opentelemetry.io/otel/attribute/kv.go similarity index 67% rename from vendor/go.opentelemetry.io/otel/label/kv.go rename to vendor/go.opentelemetry.io/otel/attribute/kv.go index 3e2764f47357..2fcc8863f733 100644 --- a/vendor/go.opentelemetry.io/otel/label/kv.go +++ b/vendor/go.opentelemetry.io/otel/attribute/kv.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package label +package attribute // import "go.opentelemetry.io/otel/attribute" import ( "encoding/json" @@ -26,6 +26,11 @@ type KeyValue struct { Value Value } +// Valid returns if kv is a valid OpenTelemetry attribute. +func (kv KeyValue) Valid() bool { + return kv.Key != "" && kv.Value.Type() != INVALID +} + // Bool creates a new key-value pair with a passed name and a bool // value. func Bool(k string, v bool) KeyValue { @@ -38,36 +43,12 @@ func Int64(k string, v int64) KeyValue { return Key(k).Int64(v) } -// Uint64 creates a new key-value pair with a passed name and a uint64 -// value. -func Uint64(k string, v uint64) KeyValue { - return Key(k).Uint64(v) -} - // Float64 creates a new key-value pair with a passed name and a float64 // value. func Float64(k string, v float64) KeyValue { return Key(k).Float64(v) } -// Int32 creates a new key-value pair with a passed name and an int32 -// value. -func Int32(k string, v int32) KeyValue { - return Key(k).Int32(v) -} - -// Uint32 creates a new key-value pair with a passed name and a uint32 -// value. -func Uint32(k string, v uint32) KeyValue { - return Key(k).Uint32(v) -} - -// Float32 creates a new key-value pair with a passed name and a float32 -// value. -func Float32(k string, v float32) KeyValue { - return Key(k).Float32(v) -} - // String creates a new key-value pair with a passed name and a string // value. func String(k, v string) KeyValue { @@ -87,13 +68,6 @@ func Int(k string, v int) KeyValue { return Key(k).Int(v) } -// Uint creates a new key-value pair instance with a passed name and -// either an uint32 or an uint64 value, depending on whether the uint -// type is 32 or 64 bits wide. -func Uint(k string, v uint) KeyValue { - return Key(k).Uint(v) -} - // Array creates a new key-value pair with a passed name and a array. // Only arrays of primitive type are supported. func Array(k string, v interface{}) KeyValue { @@ -120,24 +94,14 @@ func Any(k string, value interface{}) KeyValue { return Bool(k, rv.Bool()) case reflect.Int, reflect.Int8, reflect.Int16: return Int(k, int(rv.Int())) - case reflect.Int32: - return Int32(k, int32(rv.Int())) case reflect.Int64: - return Int64(k, int64(rv.Int())) - case reflect.Uint, reflect.Uint8, reflect.Uint16: - return Uint(k, uint(rv.Uint())) - case reflect.Uint32: - return Uint32(k, uint32(rv.Uint())) - case reflect.Uint64, reflect.Uintptr: - return Uint64(k, rv.Uint()) - case reflect.Float32: - return Float32(k, float32(rv.Float())) + return Int64(k, rv.Int()) case reflect.Float64: return Float64(k, rv.Float()) case reflect.String: return String(k, rv.String()) } - if b, err := json.Marshal(value); value != nil && err == nil { + if b, err := json.Marshal(value); b != nil && err == nil { return String(k, string(b)) } return String(k, fmt.Sprint(value)) diff --git a/vendor/go.opentelemetry.io/otel/label/set.go b/vendor/go.opentelemetry.io/otel/attribute/set.go similarity index 97% rename from vendor/go.opentelemetry.io/otel/label/set.go rename to vendor/go.opentelemetry.io/otel/attribute/set.go index 3bd5263cbd37..882dc112f728 100644 --- a/vendor/go.opentelemetry.io/otel/label/set.go +++ b/vendor/go.opentelemetry.io/otel/attribute/set.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package label +package attribute // import "go.opentelemetry.io/otel/attribute" import ( "encoding/json" @@ -78,6 +78,9 @@ var ( const maxConcurrentEncoders = 3 +// EmptySet returns a reference to a Set with no elements. +// +// This is a convenience provided for optimized calling utility. func EmptySet() *Set { return emptySet } @@ -292,7 +295,7 @@ func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) { // - allocating a `Set` for storing the return value of this // constructor. // -// The result maintains a cache of encoded labels, by label.EncoderID. +// The result maintains a cache of encoded labels, by attribute.EncoderID. // This value should not be copied after its first use. // // The second `[]KeyValue` return value is a list of labels that were diff --git a/vendor/go.opentelemetry.io/otel/label/type_string.go b/vendor/go.opentelemetry.io/otel/attribute/type_string.go similarity index 61% rename from vendor/go.opentelemetry.io/otel/label/type_string.go rename to vendor/go.opentelemetry.io/otel/attribute/type_string.go index 62afeb60af73..1f2c7dccfa51 100644 --- a/vendor/go.opentelemetry.io/otel/label/type_string.go +++ b/vendor/go.opentelemetry.io/otel/attribute/type_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type=Type"; DO NOT EDIT. -package label +package attribute import "strconv" @@ -10,19 +10,15 @@ func _() { var x [1]struct{} _ = x[INVALID-0] _ = x[BOOL-1] - _ = x[INT32-2] - _ = x[INT64-3] - _ = x[UINT32-4] - _ = x[UINT64-5] - _ = x[FLOAT32-6] - _ = x[FLOAT64-7] - _ = x[STRING-8] - _ = x[ARRAY-9] + _ = x[INT64-2] + _ = x[FLOAT64-3] + _ = x[STRING-4] + _ = x[ARRAY-5] } -const _Type_name = "INVALIDBOOLINT32INT64UINT32UINT64FLOAT32FLOAT64STRINGARRAY" +const _Type_name = "INVALIDBOOLINT64FLOAT64STRINGARRAY" -var _Type_index = [...]uint8{0, 7, 11, 16, 21, 27, 33, 40, 47, 53, 58} +var _Type_index = [...]uint8{0, 7, 11, 16, 23, 29, 34} func (i Type) String() string { if i < 0 || i >= Type(len(_Type_index)-1) { diff --git a/vendor/go.opentelemetry.io/otel/label/value.go b/vendor/go.opentelemetry.io/otel/attribute/value.go similarity index 51% rename from vendor/go.opentelemetry.io/otel/label/value.go rename to vendor/go.opentelemetry.io/otel/attribute/value.go index 633979f1b381..7b979409e300 100644 --- a/vendor/go.opentelemetry.io/otel/label/value.go +++ b/vendor/go.opentelemetry.io/otel/attribute/value.go @@ -12,15 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package label +package attribute // import "go.opentelemetry.io/otel/attribute" import ( "encoding/json" "fmt" "reflect" "strconv" - "strings" - "unsafe" "go.opentelemetry.io/otel/internal" ) @@ -41,16 +39,20 @@ type Value struct { } const ( - INVALID Type = iota // No value. - BOOL // Boolean value, use AsBool() to get it. - INT32 // 32 bit signed integral value, use AsInt32() to get it. - INT64 // 64 bit signed integral value, use AsInt64() to get it. - UINT32 // 32 bit unsigned integral value, use AsUint32() to get it. - UINT64 // 64 bit unsigned integral value, use AsUint64() to get it. - FLOAT32 // 32 bit floating point value, use AsFloat32() to get it. - FLOAT64 // 64 bit floating point value, use AsFloat64() to get it. - STRING // String value, use AsString() to get it. - ARRAY // Array value of arbitrary type, use AsArray() to get it. + // INVALID is used for a Value with no value set. + INVALID Type = iota + // BOOL is a boolean Type Value. + BOOL + // INT64 is a 64-bit signed integral Type Value. + INT64 + // FLOAT64 is a 64-bit floating point Type Value. + FLOAT64 + // STRING is a string Type Value. + STRING + // ARRAY is an array Type Value used to store 1-dimensional slices or + // arrays of bool, int, int32, int64, uint, uint32, uint64, float, + // float32, float64, or string types. + ARRAY ) // BoolValue creates a BOOL Value. @@ -69,14 +71,6 @@ func Int64Value(v int64) Value { } } -// Uint64Value creates a UINT64 Value. -func Uint64Value(v uint64) Value { - return Value{ - vtype: UINT64, - numeric: internal.Uint64ToRaw(v), - } -} - // Float64Value creates a FLOAT64 Value. func Float64Value(v float64) Value { return Value{ @@ -85,31 +79,7 @@ func Float64Value(v float64) Value { } } -// Int32Value creates an INT32 Value. -func Int32Value(v int32) Value { - return Value{ - vtype: INT32, - numeric: internal.Int32ToRaw(v), - } -} - -// Uint32 creates a UINT32 Value. -func Uint32Value(v uint32) Value { - return Value{ - vtype: UINT32, - numeric: internal.Uint32ToRaw(v), - } -} - -// Float32 creates a FLOAT32 Value. -func Float32Value(v float32) Value { - return Value{ - vtype: FLOAT32, - numeric: internal.Float32ToRaw(v), - } -} - -// String creates a STRING Value. +// StringValue creates a STRING Value. func StringValue(v string) Value { return Value{ vtype: STRING, @@ -117,45 +87,35 @@ func StringValue(v string) Value { } } -// Int creates either an INT32 or an INT64 Value, depending on whether -// the int type is 32 or 64 bits wide. +// IntValue creates an INT64 Value. func IntValue(v int) Value { - if unsafe.Sizeof(v) == 4 { - return Int32Value(int32(v)) - } return Int64Value(int64(v)) } -// Uint creates either a UINT32 or a UINT64 Value, depending on -// whether the uint type is 32 or 64 bits wide. -func UintValue(v uint) Value { - if unsafe.Sizeof(v) == 4 { - return Uint32Value(uint32(v)) - } - return Uint64Value(uint64(v)) -} - -// Array creates an ARRAY value. -func ArrayValue(array interface{}) Value { - switch reflect.TypeOf(array).Kind() { +// ArrayValue creates an ARRAY value from an array or slice. +// Only arrays or slices of bool, int, int64, float, float64, or string types are allowed. +// Specifically, arrays and slices can not contain other arrays, slices, structs, or non-standard +// types. If the passed value is not an array or slice of these types an +// INVALID value is returned. +func ArrayValue(v interface{}) Value { + switch reflect.TypeOf(v).Kind() { case reflect.Array, reflect.Slice: - isValidType := func() bool { - // get array type regardless of dimensions - typeName := reflect.TypeOf(array).String() - typeName = typeName[strings.LastIndex(typeName, "]")+1:] - switch typeName { - case "bool", "int", "int32", "int64", - "float32", "float64", "string", - "uint", "uint32", "uint64": - return true - } - return false - }() - if isValidType { + // get array type regardless of dimensions + typ := reflect.TypeOf(v).Elem() + kind := typ.Kind() + switch kind { + case reflect.Bool, reflect.Int, reflect.Int64, + reflect.Float64, reflect.String: + val := reflect.ValueOf(v) + length := val.Len() + frozen := reflect.Indirect(reflect.New(reflect.ArrayOf(length, typ))) + reflect.Copy(frozen, val) return Value{ vtype: ARRAY, - array: array, + array: frozen.Interface(), } + default: + return Value{vtype: INVALID} } } return Value{vtype: INVALID} @@ -172,36 +132,12 @@ func (v Value) AsBool() bool { return internal.RawToBool(v.numeric) } -// AsInt32 returns the int32 value. Make sure that the Value's type is -// INT32. -func (v Value) AsInt32() int32 { - return internal.RawToInt32(v.numeric) -} - // AsInt64 returns the int64 value. Make sure that the Value's type is // INT64. func (v Value) AsInt64() int64 { return internal.RawToInt64(v.numeric) } -// AsUint32 returns the uint32 value. Make sure that the Value's type -// is UINT32. -func (v Value) AsUint32() uint32 { - return internal.RawToUint32(v.numeric) -} - -// AsUint64 returns the uint64 value. Make sure that the Value's type is -// UINT64. -func (v Value) AsUint64() uint64 { - return internal.RawToUint64(v.numeric) -} - -// AsFloat32 returns the float32 value. Make sure that the Value's -// type is FLOAT32. -func (v Value) AsFloat32() float32 { - return internal.RawToFloat32(v.numeric) -} - // AsFloat64 returns the float64 value. Make sure that the Value's // type is FLOAT64. func (v Value) AsFloat64() float64 { @@ -228,16 +164,8 @@ func (v Value) AsInterface() interface{} { return v.AsArray() case BOOL: return v.AsBool() - case INT32: - return v.AsInt32() case INT64: return v.AsInt64() - case UINT32: - return v.AsUint32() - case UINT64: - return v.AsUint64() - case FLOAT32: - return v.AsFloat32() case FLOAT64: return v.AsFloat64() case STRING: @@ -253,16 +181,8 @@ func (v Value) Emit() string { return fmt.Sprint(v.array) case BOOL: return strconv.FormatBool(v.AsBool()) - case INT32: - return strconv.FormatInt(int64(v.AsInt32()), 10) case INT64: return strconv.FormatInt(v.AsInt64(), 10) - case UINT32: - return strconv.FormatUint(uint64(v.AsUint32()), 10) - case UINT64: - return strconv.FormatUint(v.AsUint64(), 10) - case FLOAT32: - return fmt.Sprint(v.AsFloat32()) case FLOAT64: return fmt.Sprint(v.AsFloat64()) case STRING: diff --git a/vendor/go.opentelemetry.io/otel/codes/codes.go b/vendor/go.opentelemetry.io/otel/codes/codes.go index 7d4aaee22c93..064a9279fd14 100644 --- a/vendor/go.opentelemetry.io/otel/codes/codes.go +++ b/vendor/go.opentelemetry.io/otel/codes/codes.go @@ -12,78 +12,95 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package codes defines the canonical error codes used by OpenTelemetry. -// -// It conforms to [the OpenTelemetry -// specification](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#statuscanonicalcode). -// This also means that it follows gRPC codes and is based on -// [google.golang.org/grpc/codes](https://godoc.org/google.golang.org/grpc/codes). -// -// This package was added to this project, instead of using that existing -// package, to avoid the large package size it includes and not impose that -// burden on projects using this package. -package codes +package codes // import "go.opentelemetry.io/otel/codes" -// Code is an 32-bit representation of a status state. -type Code uint32 +import ( + "encoding/json" + "fmt" + "strconv" +) -// WARNING: any changes here must be propagated to the -// otel/sdk/internal/codes.go file. const ( - // OK means success. - OK Code = 0 - // Canceled indicates the operation was canceled (typically by the - // caller). - Canceled Code = 1 - // Unknown error. An example of where this error may be returned is if an - // error is raised by a dependant API that does not contain enough - // information to convert it into a more appropriate error. - Unknown Code = 2 - // InvalidArgument indicates a client specified an invalid argument. Note - // that this differs from FailedPrecondition. InvalidArgument indicates - // arguments that are problematic regardless of the state of the system. - InvalidArgument Code = 3 - // DeadlineExceeded means a deadline expired before the operation could - // complete. For operations that change the state of the system, this error - // may be returned even if the operation has completed successfully. - DeadlineExceeded Code = 4 - // NotFound means some requested entity (e.g., file or directory) was not - // found. - NotFound Code = 5 - // AlreadyExists means some entity that we attempted to create (e.g., file - // or directory) already exists. - AlreadyExists Code = 6 - // PermissionDenied means the caller does not have permission to execute - // the specified operation. PermissionDenied must not be used if the caller - // cannot be identified (use Unauthenticated instead for those errors). - PermissionDenied Code = 7 - // ResourceExhausted means some resource has been exhausted, perhaps a - // per-user quota, or perhaps the entire file system is out of space. - ResourceExhausted Code = 8 - // FailedPrecondition means the operation was rejected because the system - // is not in a state required for the operation's execution. - FailedPrecondition Code = 9 - // Aborted means the operation was aborted, typically due to a concurrency - // issue like sequencer check failures, transaction aborts, etc. - Aborted Code = 10 - // OutOfRange means the operation was attempted past the valid range. - // E.g., seeking or reading past end of file. Unlike InvalidArgument, this - // error indicates a problem that may be fixed if the system state - // changes. - OutOfRange Code = 11 - // Unimplemented means the operation is not implemented or not - // supported/enabled in this service. - Unimplemented Code = 12 - // Internal means an internal errors. It means some invariants expected by - // underlying system has been broken. - Internal Code = 13 - // Unavailable means the service is currently unavailable. This is most - // likely a transient condition and may be corrected by retrying with a - // backoff. - Unavailable Code = 14 - // DataLoss means unrecoverable data loss or corruption has occurred. - DataLoss Code = 15 - // Unauthenticated means the request does not have valid authentication - // credentials for the operation. - Unauthenticated Code = 16 + // Unset is the default status code. + Unset Code = 0 + // Error indicates the operation contains an error. + Error Code = 1 + // Ok indicates operation has been validated by an Application developers + // or Operator to have completed successfully, or contain no error. + Ok Code = 2 + + maxCode = 3 ) + +// Code is an 32-bit representation of a status state. +type Code uint32 + +var codeToStr = map[Code]string{ + Unset: "Unset", + Error: "Error", + Ok: "Ok", +} + +var strToCode = map[string]Code{ + `"Unset"`: Unset, + `"Error"`: Error, + `"Ok"`: Ok, +} + +// String returns the Code as a string. +func (c Code) String() string { + return codeToStr[c] +} + +// UnmarshalJSON unmarshals b into the Code. +// +// This is based on the functionality in the gRPC codes package: +// https://github.com/grpc/grpc-go/blob/bb64fee312b46ebee26be43364a7a966033521b1/codes/codes.go#L218-L244 +func (c *Code) UnmarshalJSON(b []byte) error { + // From json.Unmarshaler: By convention, to approximate the behavior of + // Unmarshal itself, Unmarshalers implement UnmarshalJSON([]byte("null")) as + // a no-op. + if string(b) == "null" { + return nil + } + if c == nil { + return fmt.Errorf("nil receiver passed to UnmarshalJSON") + } + + var x interface{} + if err := json.Unmarshal(b, &x); err != nil { + return err + } + switch x.(type) { + case string: + if jc, ok := strToCode[string(b)]; ok { + *c = jc + return nil + } + return fmt.Errorf("invalid code: %q", string(b)) + case float64: + if ci, err := strconv.ParseUint(string(b), 10, 32); err == nil { + if ci >= maxCode { + return fmt.Errorf("invalid code: %q", ci) + } + + *c = Code(ci) + return nil + } + return fmt.Errorf("invalid code: %q", string(b)) + default: + return fmt.Errorf("invalid code: %q", string(b)) + } +} + +// MarshalJSON returns c as the JSON encoding of c. +func (c *Code) MarshalJSON() ([]byte, error) { + if c == nil { + return []byte("null"), nil + } + str, ok := codeToStr[*c] + if !ok { + return nil, fmt.Errorf("invalid code: %d", *c) + } + return []byte(fmt.Sprintf("%q", str)), nil +} diff --git a/vendor/go.opentelemetry.io/otel/api/global/propagation.go b/vendor/go.opentelemetry.io/otel/codes/doc.go similarity index 53% rename from vendor/go.opentelemetry.io/otel/api/global/propagation.go rename to vendor/go.opentelemetry.io/otel/codes/doc.go index e3090293dae0..fcf89ba1ac0c 100644 --- a/vendor/go.opentelemetry.io/otel/api/global/propagation.go +++ b/vendor/go.opentelemetry.io/otel/codes/doc.go @@ -12,21 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global +/* +Package codes defines the canonical error codes used by OpenTelemetry. -import ( - "go.opentelemetry.io/otel/api/global/internal" - "go.opentelemetry.io/otel/api/propagation" -) +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track +the evolving OpenTelemetry specification and user feedback. -// Propagators returns the registered global propagators instance. If -// none is registered then an instance of propagators.NoopPropagators -// is returned. -func Propagators() propagation.Propagators { - return internal.Propagators() -} - -// SetPropagators registers `p` as the global propagators instance. -func SetPropagators(p propagation.Propagators) { - internal.SetPropagators(p) -} +It conforms to [the OpenTelemetry +specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#statuscanonicalcode). +*/ +package codes // import "go.opentelemetry.io/otel/codes" diff --git a/vendor/go.opentelemetry.io/otel/doc.go b/vendor/go.opentelemetry.io/otel/doc.go index af2e5e4d3fa0..771ce81cc2f0 100644 --- a/vendor/go.opentelemetry.io/otel/doc.go +++ b/vendor/go.opentelemetry.io/otel/doc.go @@ -12,4 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. +/* +Package otel provides global access to the OpenTelemetry API. The subpackages of +the otel package provide an implementation of the OpenTelemetry API. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. + +The provided API is used to instrument code and measure data about that code's +performance and operation. The measured data, by default, is not processed or +transmitted anywhere. An implementation of the OpenTelemetry SDK, like the +default SDK implementation (go.opentelemetry.io/otel/sdk), and associated +exporters are used to process and transport this data. + +To read the getting started guide, see https://opentelemetry.io/docs/go/getting-started/. + +To read more about tracing, see go.opentelemetry.io/otel/trace. + +To read more about metrics, see go.opentelemetry.io/otel/metric. + +To read more about propagation, see go.opentelemetry.io/otel/propagation and +go.opentelemetry.io/otel/baggage. +*/ package otel // import "go.opentelemetry.io/otel" diff --git a/vendor/go.opentelemetry.io/otel/error_handler.go b/vendor/go.opentelemetry.io/otel/error_handler.go index 3c5604917a2c..ac42f8be0723 100644 --- a/vendor/go.opentelemetry.io/otel/error_handler.go +++ b/vendor/go.opentelemetry.io/otel/error_handler.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package otel +package otel // import "go.opentelemetry.io/otel" // ErrorHandler handles irremediable events. type ErrorHandler interface { diff --git a/vendor/go.opentelemetry.io/otel/get_main_pkgs.sh b/vendor/go.opentelemetry.io/otel/get_main_pkgs.sh index d1c892f0eafc..9a58fb1d372e 100644 --- a/vendor/go.opentelemetry.io/otel/get_main_pkgs.sh +++ b/vendor/go.opentelemetry.io/otel/get_main_pkgs.sh @@ -23,14 +23,19 @@ fi p=$(pwd) mod_dirs=() -mapfile -t mod_dirs < <(find "${top_dir}" -type f -name 'go.mod' -exec dirname {} \; | sort) + +# Note `mapfile` does not exist in older bash versions: +# https://stackoverflow.com/questions/41475261/need-alternative-to-readarray-mapfile-for-script-on-older-version-of-bash + +while IFS= read -r line; do + mod_dirs+=("$line") +done < <(find "${top_dir}" -type f -name 'go.mod' -exec dirname {} \; | sort) for mod_dir in "${mod_dirs[@]}"; do cd "${mod_dir}" - main_dirs=() - mapfile -t main_dirs < <(go list --find -f '{{.Name}}|{{.Dir}}' ./... | grep '^main|' | cut -f 2- -d '|') - for main_dir in "${main_dirs[@]}"; do - echo ".${main_dir#${p}}" - done + + while IFS= read -r line; do + echo ".${line#${p}}" + done < <(go list --find -f '{{.Name}}|{{.Dir}}' ./... | grep '^main|' | cut -f 2- -d '|') cd "${p}" done diff --git a/vendor/go.opentelemetry.io/otel/go.mod b/vendor/go.opentelemetry.io/otel/go.mod index dc10203c6df6..a0e9267ad36a 100644 --- a/vendor/go.opentelemetry.io/otel/go.mod +++ b/vendor/go.opentelemetry.io/otel/go.mod @@ -3,6 +3,53 @@ module go.opentelemetry.io/otel go 1.14 require ( - github.com/google/go-cmp v0.5.1 - github.com/stretchr/testify v1.6.1 + github.com/google/go-cmp v0.5.5 + github.com/stretchr/testify v1.7.0 + go.opentelemetry.io/otel/metric v0.20.0 + go.opentelemetry.io/otel/oteltest v0.20.0 + go.opentelemetry.io/otel/trace v0.20.0 ) + +replace go.opentelemetry.io/otel => ./ + +replace go.opentelemetry.io/otel/bridge/opencensus => ./bridge/opencensus + +replace go.opentelemetry.io/otel/bridge/opentracing => ./bridge/opentracing + +replace go.opentelemetry.io/otel/example/jaeger => ./example/jaeger + +replace go.opentelemetry.io/otel/example/namedtracer => ./example/namedtracer + +replace go.opentelemetry.io/otel/example/opencensus => ./example/opencensus + +replace go.opentelemetry.io/otel/example/otel-collector => ./example/otel-collector + +replace go.opentelemetry.io/otel/example/prom-collector => ./example/prom-collector + +replace go.opentelemetry.io/otel/example/prometheus => ./example/prometheus + +replace go.opentelemetry.io/otel/example/zipkin => ./example/zipkin + +replace go.opentelemetry.io/otel/exporters/metric/prometheus => ./exporters/metric/prometheus + +replace go.opentelemetry.io/otel/exporters/otlp => ./exporters/otlp + +replace go.opentelemetry.io/otel/exporters/stdout => ./exporters/stdout + +replace go.opentelemetry.io/otel/exporters/trace/jaeger => ./exporters/trace/jaeger + +replace go.opentelemetry.io/otel/exporters/trace/zipkin => ./exporters/trace/zipkin + +replace go.opentelemetry.io/otel/internal/tools => ./internal/tools + +replace go.opentelemetry.io/otel/sdk => ./sdk + +replace go.opentelemetry.io/otel/metric => ./metric + +replace go.opentelemetry.io/otel/oteltest => ./oteltest + +replace go.opentelemetry.io/otel/sdk/export/metric => ./sdk/export/metric + +replace go.opentelemetry.io/otel/sdk/metric => ./sdk/metric + +replace go.opentelemetry.io/otel/trace => ./trace diff --git a/vendor/go.opentelemetry.io/otel/go.sum b/vendor/go.opentelemetry.io/otel/go.sum index 741ca4ea29bd..b69f2e56da0f 100644 --- a/vendor/go.opentelemetry.io/otel/go.sum +++ b/vendor/go.opentelemetry.io/otel/go.sum @@ -1,12 +1,12 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/vendor/go.opentelemetry.io/otel/api/global/handler.go b/vendor/go.opentelemetry.io/otel/handler.go similarity index 82% rename from vendor/go.opentelemetry.io/otel/api/global/handler.go rename to vendor/go.opentelemetry.io/otel/handler.go index 83f3e523a9a3..27e1caa30d9f 100644 --- a/vendor/go.opentelemetry.io/otel/api/global/handler.go +++ b/vendor/go.opentelemetry.io/otel/handler.go @@ -12,15 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global +package otel // import "go.opentelemetry.io/otel" import ( "log" "os" "sync" "sync/atomic" - - "go.opentelemetry.io/otel" ) var ( @@ -37,7 +35,7 @@ var ( delegateErrorHandlerOnce sync.Once // Comiple time check that loggingErrorHandler implements ErrorHandler. - _ otel.ErrorHandler = (*loggingErrorHandler)(nil) + _ ErrorHandler = (*loggingErrorHandler)(nil) ) // loggingErrorHandler logs all errors to STDERR. @@ -48,7 +46,7 @@ type loggingErrorHandler struct { } // setDelegate sets the ErrorHandler delegate if one is not already set. -func (h *loggingErrorHandler) setDelegate(d otel.ErrorHandler) { +func (h *loggingErrorHandler) setDelegate(d ErrorHandler) { if h.delegate.Load() != nil { // Delegate already registered return @@ -56,26 +54,26 @@ func (h *loggingErrorHandler) setDelegate(d otel.ErrorHandler) { h.delegate.Store(d) } -// Handle implements otel.ErrorHandler. +// Handle implements ErrorHandler. func (h *loggingErrorHandler) Handle(err error) { if d := h.delegate.Load(); d != nil { - d.(otel.ErrorHandler).Handle(err) + d.(ErrorHandler).Handle(err) return } h.l.Print(err) } -// ErrorHandler returns the global ErrorHandler instance. If no ErrorHandler +// GetErrorHandler returns the global ErrorHandler instance. If no ErrorHandler // instance has been set (`SetErrorHandler`), the default ErrorHandler which // logs errors to STDERR is returned. -func ErrorHandler() otel.ErrorHandler { +func GetErrorHandler() ErrorHandler { return globalErrorHandler } // SetErrorHandler sets the global ErrorHandler to be h. -func SetErrorHandler(h otel.ErrorHandler) { +func SetErrorHandler(h ErrorHandler) { delegateErrorHandlerOnce.Do(func() { - current := ErrorHandler() + current := GetErrorHandler() if current == h { return } @@ -87,5 +85,5 @@ func SetErrorHandler(h otel.ErrorHandler) { // Handle is a convience function for ErrorHandler().Handle(err) func Handle(err error) { - ErrorHandler().Handle(err) + GetErrorHandler().Handle(err) } diff --git a/vendor/go.opentelemetry.io/otel/api/correlation/context.go b/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go similarity index 55% rename from vendor/go.opentelemetry.io/otel/api/correlation/context.go rename to vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go index ee3841984817..b1f7daf8d86a 100644 --- a/vendor/go.opentelemetry.io/otel/api/correlation/context.go +++ b/vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go @@ -12,14 +12,174 @@ // See the License for the specific language governing permissions and // limitations under the License. -package correlation +// Package baggage provides types and functions to manage W3C Baggage. +package baggage import ( "context" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" ) +type rawMap map[attribute.Key]attribute.Value +type keySet map[attribute.Key]struct{} + +// Map is an immutable storage for correlations. +type Map struct { + m rawMap +} + +// MapUpdate contains information about correlation changes to be +// made. +type MapUpdate struct { + // DropSingleK contains a single key to be dropped from + // correlations. Use this to avoid an overhead of a slice + // allocation if there is only one key to drop. + DropSingleK attribute.Key + // DropMultiK contains all the keys to be dropped from + // correlations. + DropMultiK []attribute.Key + + // SingleKV contains a single key-value pair to be added to + // correlations. Use this to avoid an overhead of a slice + // allocation if there is only one key-value pair to add. + SingleKV attribute.KeyValue + // MultiKV contains all the key-value pairs to be added to + // correlations. + MultiKV []attribute.KeyValue +} + +func newMap(raw rawMap) Map { + return Map{ + m: raw, + } +} + +// NewEmptyMap creates an empty correlations map. +func NewEmptyMap() Map { + return newMap(nil) +} + +// NewMap creates a map with the contents of the update applied. In +// this function, having an update with DropSingleK or DropMultiK +// makes no sense - those fields are effectively ignored. +func NewMap(update MapUpdate) Map { + return NewEmptyMap().Apply(update) +} + +// Apply creates a copy of the map with the contents of the update +// applied. Apply will first drop the keys from DropSingleK and +// DropMultiK, then add key-value pairs from SingleKV and MultiKV. +func (m Map) Apply(update MapUpdate) Map { + delSet, addSet := getModificationSets(update) + mapSize := getNewMapSize(m.m, delSet, addSet) + + r := make(rawMap, mapSize) + for k, v := range m.m { + // do not copy items we want to drop + if _, ok := delSet[k]; ok { + continue + } + // do not copy items we would overwrite + if _, ok := addSet[k]; ok { + continue + } + r[k] = v + } + if update.SingleKV.Key.Defined() { + r[update.SingleKV.Key] = update.SingleKV.Value + } + for _, kv := range update.MultiKV { + r[kv.Key] = kv.Value + } + if len(r) == 0 { + r = nil + } + return newMap(r) +} + +func getModificationSets(update MapUpdate) (delSet, addSet keySet) { + deletionsCount := len(update.DropMultiK) + if update.DropSingleK.Defined() { + deletionsCount++ + } + if deletionsCount > 0 { + delSet = make(map[attribute.Key]struct{}, deletionsCount) + for _, k := range update.DropMultiK { + delSet[k] = struct{}{} + } + if update.DropSingleK.Defined() { + delSet[update.DropSingleK] = struct{}{} + } + } + + additionsCount := len(update.MultiKV) + if update.SingleKV.Key.Defined() { + additionsCount++ + } + if additionsCount > 0 { + addSet = make(map[attribute.Key]struct{}, additionsCount) + for _, k := range update.MultiKV { + addSet[k.Key] = struct{}{} + } + if update.SingleKV.Key.Defined() { + addSet[update.SingleKV.Key] = struct{}{} + } + } + + return +} + +func getNewMapSize(m rawMap, delSet, addSet keySet) int { + mapSizeDiff := 0 + for k := range addSet { + if _, ok := m[k]; !ok { + mapSizeDiff++ + } + } + for k := range delSet { + if _, ok := m[k]; ok { + if _, inAddSet := addSet[k]; !inAddSet { + mapSizeDiff-- + } + } + } + return len(m) + mapSizeDiff +} + +// Value gets a value from correlations map and returns a boolean +// value indicating whether the key exist in the map. +func (m Map) Value(k attribute.Key) (attribute.Value, bool) { + value, ok := m.m[k] + return value, ok +} + +// HasValue returns a boolean value indicating whether the key exist +// in the map. +func (m Map) HasValue(k attribute.Key) bool { + _, has := m.Value(k) + return has +} + +// Len returns a length of the map. +func (m Map) Len() int { + return len(m.m) +} + +// Foreach calls a passed callback once on each key-value pair until +// all the key-value pairs of the map were iterated or the callback +// returns false, whichever happens first. +func (m Map) Foreach(f func(attribute.KeyValue) bool) { + for k, v := range m.m { + if !f(attribute.KeyValue{ + Key: k, + Value: v, + }) { + return + } + } +} + type correlationsType struct{} // SetHookFunc describes a type of a callback that is called when @@ -148,9 +308,15 @@ func ContextWithMap(ctx context.Context, m Map) context.Context { } } +// ContextWithNoCorrelationData returns a context stripped of correlation +// data. +func ContextWithNoCorrelationData(ctx context.Context) context.Context { + return context.WithValue(ctx, correlationsKey, nil) +} + // NewContext returns a context with the map from passed context // updated with the passed key-value pairs. -func NewContext(ctx context.Context, keyvalues ...label.KeyValue) context.Context { +func NewContext(ctx context.Context, keyvalues ...attribute.KeyValue) context.Context { return ContextWithMap(ctx, MapFromContext(ctx).Apply(MapUpdate{ MultiKV: keyvalues, })) diff --git a/vendor/go.opentelemetry.io/otel/api/global/internal/meter.go b/vendor/go.opentelemetry.io/otel/internal/global/meter.go similarity index 83% rename from vendor/go.opentelemetry.io/otel/api/global/internal/meter.go rename to vendor/go.opentelemetry.io/otel/internal/global/meter.go index ce3ed20996cf..36f9edeb8c6b 100644 --- a/vendor/go.opentelemetry.io/otel/api/global/internal/meter.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/meter.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal +package global import ( "context" @@ -20,24 +20,25 @@ import ( "sync/atomic" "unsafe" - "go.opentelemetry.io/otel/api/metric" - "go.opentelemetry.io/otel/api/metric/registry" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/number" + "go.opentelemetry.io/otel/metric/registry" ) -// This file contains the forwarding implementation of metric.Provider -// used as the default global instance. Metric events using instruments -// provided by this implementation are no-ops until the first Meter -// implementation is set as the global provider. +// This file contains the forwarding implementation of MeterProvider used as +// the default global instance. Metric events using instruments provided by +// this implementation are no-ops until the first Meter implementation is set +// as the global provider. // -// The implementation here uses Mutexes to maintain a list of active -// Meters in the Provider and Instruments in each Meter, under the -// assumption that these interfaces are not performance-critical. +// The implementation here uses Mutexes to maintain a list of active Meters in +// the MeterProvider and Instruments in each Meter, under the assumption that +// these interfaces are not performance-critical. // -// We have the invariant that setDelegate() will be called before a -// new metric.Provider implementation is registered as the global -// provider. Mutexes in the Provider and Meters ensure that each -// instrument has a delegate before the global provider is set. +// We have the invariant that setDelegate() will be called before a new +// MeterProvider implementation is registered as the global provider. Mutexes +// in the MeterProvider and Meters ensure that each instrument has a delegate +// before the global provider is set. // // Bound instrument operations are implemented by delegating to the // instrument after it is registered, with a sync.Once initializer to @@ -51,7 +52,7 @@ type meterKey struct { } type meterProvider struct { - delegate metric.Provider + delegate metric.MeterProvider // lock protects `delegate` and `meters`. lock sync.Mutex @@ -105,15 +106,15 @@ type AsyncImpler interface { } type syncHandle struct { - delegate unsafe.Pointer // (*metric.HandleImpl) + delegate unsafe.Pointer // (*metric.BoundInstrumentImpl) inst *syncImpl - labels []label.KeyValue + labels []attribute.KeyValue initialize sync.Once } -var _ metric.Provider = &meterProvider{} +var _ metric.MeterProvider = &meterProvider{} var _ metric.MeterImpl = &meterImpl{} var _ metric.InstrumentImpl = &syncImpl{} var _ metric.BoundSyncImpl = &syncHandle{} @@ -123,7 +124,7 @@ func (inst *instrument) Descriptor() metric.Descriptor { return inst.descriptor } -// Provider interface and delegation +// MeterProvider interface and delegation func newMeterProvider() *meterProvider { return &meterProvider{ @@ -131,7 +132,7 @@ func newMeterProvider() *meterProvider { } } -func (p *meterProvider) setDelegate(provider metric.Provider) { +func (p *meterProvider) setDelegate(provider metric.MeterProvider) { p.lock.Lock() defer p.lock.Unlock() @@ -152,7 +153,7 @@ func (p *meterProvider) Meter(instrumentationName string, opts ...metric.MeterOp key := meterKey{ Name: instrumentationName, - Version: metric.ConfigureMeter(opts).InstrumentationVersion, + Version: metric.NewMeterConfig(opts...).InstrumentationVersion, } entry, ok := p.meters[key] if !ok { @@ -166,7 +167,7 @@ func (p *meterProvider) Meter(instrumentationName string, opts ...metric.MeterOp // Meter interface and delegation -func (m *meterImpl) setDelegate(name, version string, provider metric.Provider) { +func (m *meterImpl) setDelegate(name, version string, provider metric.MeterProvider) { m.lock.Lock() defer m.lock.Unlock() @@ -227,7 +228,7 @@ func (inst *syncImpl) Implementation() interface{} { return inst } -func (inst *syncImpl) Bind(labels []label.KeyValue) metric.BoundSyncImpl { +func (inst *syncImpl) Bind(labels []attribute.KeyValue) metric.BoundSyncImpl { if implPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { return (*implPtr).Bind(labels) } @@ -299,13 +300,13 @@ func (obs *asyncImpl) setDelegate(d metric.MeterImpl) { // Metric updates -func (m *meterImpl) RecordBatch(ctx context.Context, labels []label.KeyValue, measurements ...metric.Measurement) { +func (m *meterImpl) RecordBatch(ctx context.Context, labels []attribute.KeyValue, measurements ...metric.Measurement) { if delegatePtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { (*delegatePtr).RecordBatch(ctx, labels, measurements...) } } -func (inst *syncImpl) RecordOne(ctx context.Context, number metric.Number, labels []label.KeyValue) { +func (inst *syncImpl) RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) { if instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); instPtr != nil { (*instPtr).RecordOne(ctx, number, labels) } @@ -313,7 +314,7 @@ func (inst *syncImpl) RecordOne(ctx context.Context, number metric.Number, label // Bound instrument initialization -func (bound *syncHandle) RecordOne(ctx context.Context, number metric.Number) { +func (bound *syncHandle) RecordOne(ctx context.Context, number number.Number) { instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&bound.inst.delegate)) if instPtr == nil { return diff --git a/vendor/go.opentelemetry.io/otel/internal/global/propagator.go b/vendor/go.opentelemetry.io/otel/internal/global/propagator.go new file mode 100644 index 000000000000..1c8b8589b08c --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/internal/global/propagator.go @@ -0,0 +1,82 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package global + +import ( + "context" + "sync" + + "go.opentelemetry.io/otel/propagation" +) + +// textMapPropagator is a default TextMapPropagator that delegates calls to a +// registered delegate if one is set, otherwise it defaults to delegating the +// calls to a the default no-op propagation.TextMapPropagator. +type textMapPropagator struct { + mtx sync.Mutex + once sync.Once + delegate propagation.TextMapPropagator + noop propagation.TextMapPropagator +} + +// Compile-time guarantee that textMapPropagator implements the +// propagation.TextMapPropagator interface. +var _ propagation.TextMapPropagator = (*textMapPropagator)(nil) + +func newTextMapPropagator() *textMapPropagator { + return &textMapPropagator{ + noop: propagation.NewCompositeTextMapPropagator(), + } +} + +// SetDelegate sets a delegate propagation.TextMapPropagator that all calls are +// forwarded to. Delegation can only be performed once, all subsequent calls +// perform no delegation. +func (p *textMapPropagator) SetDelegate(delegate propagation.TextMapPropagator) { + if delegate == nil { + return + } + + p.mtx.Lock() + p.once.Do(func() { p.delegate = delegate }) + p.mtx.Unlock() +} + +// effectiveDelegate returns the current delegate of p if one is set, +// otherwise the default noop TextMapPropagator is returned. This method +// can be called concurrently. +func (p *textMapPropagator) effectiveDelegate() propagation.TextMapPropagator { + p.mtx.Lock() + defer p.mtx.Unlock() + if p.delegate != nil { + return p.delegate + } + return p.noop +} + +// Inject set cross-cutting concerns from the Context into the carrier. +func (p *textMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { + p.effectiveDelegate().Inject(ctx, carrier) +} + +// Extract reads cross-cutting concerns from the carrier into a Context. +func (p *textMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { + return p.effectiveDelegate().Extract(ctx, carrier) +} + +// Fields returns the keys whose values are set with Inject. +func (p *textMapPropagator) Fields() []string { + return p.effectiveDelegate().Fields() +} diff --git a/vendor/go.opentelemetry.io/otel/api/global/internal/state.go b/vendor/go.opentelemetry.io/otel/internal/global/state.go similarity index 50% rename from vendor/go.opentelemetry.io/otel/api/global/internal/state.go rename to vendor/go.opentelemetry.io/otel/internal/global/state.go index f965aa9ccec1..f3bf0035100f 100644 --- a/vendor/go.opentelemetry.io/otel/api/global/internal/state.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/state.go @@ -12,29 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal +package global import ( "sync" "sync/atomic" - "go.opentelemetry.io/otel/api/correlation" - "go.opentelemetry.io/otel/api/metric" - "go.opentelemetry.io/otel/api/propagation" - "go.opentelemetry.io/otel/api/trace" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/trace" ) type ( - traceProviderHolder struct { - tp trace.Provider + tracerProviderHolder struct { + tp trace.TracerProvider } meterProviderHolder struct { - mp metric.Provider + mp metric.MeterProvider } propagatorsHolder struct { - pr propagation.Propagators + tm propagation.TextMapPropagator } ) @@ -43,39 +42,40 @@ var ( globalMeter = defaultMeterValue() globalPropagators = defaultPropagatorsValue() - delegateMeterOnce sync.Once - delegateTraceOnce sync.Once + delegateMeterOnce sync.Once + delegateTraceOnce sync.Once + delegateTextMapPropagatorOnce sync.Once ) -// TraceProvider is the internal implementation for global.TraceProvider. -func TraceProvider() trace.Provider { - return globalTracer.Load().(traceProviderHolder).tp +// TracerProvider is the internal implementation for global.TracerProvider. +func TracerProvider() trace.TracerProvider { + return globalTracer.Load().(tracerProviderHolder).tp } -// SetTraceProvider is the internal implementation for global.SetTraceProvider. -func SetTraceProvider(tp trace.Provider) { +// SetTracerProvider is the internal implementation for global.SetTracerProvider. +func SetTracerProvider(tp trace.TracerProvider) { delegateTraceOnce.Do(func() { - current := TraceProvider() + current := TracerProvider() if current == tp { // Setting the provider to the prior default is nonsense, panic. // Panic is acceptable because we are likely still early in the // process lifetime. - panic("invalid Provider, the global instance cannot be reinstalled") - } else if def, ok := current.(*traceProvider); ok { + panic("invalid TracerProvider, the global instance cannot be reinstalled") + } else if def, ok := current.(*tracerProvider); ok { def.setDelegate(tp) } }) - globalTracer.Store(traceProviderHolder{tp: tp}) + globalTracer.Store(tracerProviderHolder{tp: tp}) } // MeterProvider is the internal implementation for global.MeterProvider. -func MeterProvider() metric.Provider { +func MeterProvider() metric.MeterProvider { return globalMeter.Load().(meterProviderHolder).mp } // SetMeterProvider is the internal implementation for global.SetMeterProvider. -func SetMeterProvider(mp metric.Provider) { +func SetMeterProvider(mp metric.MeterProvider) { delegateMeterOnce.Do(func() { current := MeterProvider() @@ -83,7 +83,7 @@ func SetMeterProvider(mp metric.Provider) { // Setting the provider to the prior default is nonsense, panic. // Panic is acceptable because we are likely still early in the // process lifetime. - panic("invalid Provider, the global instance cannot be reinstalled") + panic("invalid MeterProvider, the global instance cannot be reinstalled") } else if def, ok := current.(*meterProvider); ok { def.setDelegate(mp) } @@ -91,19 +91,32 @@ func SetMeterProvider(mp metric.Provider) { globalMeter.Store(meterProviderHolder{mp: mp}) } -// Propagators is the internal implementation for global.Propagators. -func Propagators() propagation.Propagators { - return globalPropagators.Load().(propagatorsHolder).pr +// TextMapPropagator is the internal implementation for global.TextMapPropagator. +func TextMapPropagator() propagation.TextMapPropagator { + return globalPropagators.Load().(propagatorsHolder).tm } -// SetPropagators is the internal implementation for global.SetPropagators. -func SetPropagators(pr propagation.Propagators) { - globalPropagators.Store(propagatorsHolder{pr: pr}) +// SetTextMapPropagator is the internal implementation for global.SetTextMapPropagator. +func SetTextMapPropagator(p propagation.TextMapPropagator) { + // For the textMapPropagator already returned by TextMapPropagator + // delegate to p. + delegateTextMapPropagatorOnce.Do(func() { + if current := TextMapPropagator(); current == p { + // Setting the provider to the prior default is nonsense, panic. + // Panic is acceptable because we are likely still early in the + // process lifetime. + panic("invalid TextMapPropagator, the global instance cannot be reinstalled") + } else if def, ok := current.(*textMapPropagator); ok { + def.SetDelegate(p) + } + }) + // Return p when subsequent calls to TextMapPropagator are made. + globalPropagators.Store(propagatorsHolder{tm: p}) } func defaultTracerValue() *atomic.Value { v := &atomic.Value{} - v.Store(traceProviderHolder{tp: &traceProvider{}}) + v.Store(tracerProviderHolder{tp: &tracerProvider{}}) return v } @@ -115,21 +128,10 @@ func defaultMeterValue() *atomic.Value { func defaultPropagatorsValue() *atomic.Value { v := &atomic.Value{} - v.Store(propagatorsHolder{pr: getDefaultPropagators()}) + v.Store(propagatorsHolder{tm: newTextMapPropagator()}) return v } -// getDefaultPropagators returns a default Propagators, configured -// with W3C trace and correlation context propagation. -func getDefaultPropagators() propagation.Propagators { - tcPropagator := trace.TraceContext{} - ccPropagator := correlation.CorrelationContext{} - return propagation.New( - propagation.WithExtractors(tcPropagator, ccPropagator), - propagation.WithInjectors(tcPropagator, ccPropagator), - ) -} - // ResetForTest restores the initial global state, for testing purposes. func ResetForTest() { globalTracer = defaultTracerValue() @@ -137,4 +139,5 @@ func ResetForTest() { globalPropagators = defaultPropagatorsValue() delegateMeterOnce = sync.Once{} delegateTraceOnce = sync.Once{} + delegateTextMapPropagatorOnce = sync.Once{} } diff --git a/vendor/go.opentelemetry.io/otel/api/global/internal/trace.go b/vendor/go.opentelemetry.io/otel/internal/global/trace.go similarity index 51% rename from vendor/go.opentelemetry.io/otel/api/global/internal/trace.go rename to vendor/go.opentelemetry.io/otel/internal/global/trace.go index 69024b66769a..d7f71dc06c65 100644 --- a/vendor/go.opentelemetry.io/otel/api/global/internal/trace.go +++ b/vendor/go.opentelemetry.io/otel/internal/global/trace.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package internal +package global /* -This file contains the forwarding implementation of the trace.Provider used as +This file contains the forwarding implementation of the TracerProvider used as the default global instance. Prior to initialization of an SDK, Tracers -returned by the global Provider will provide no-op functionality. This means -that all Span created prior to initialization are no-op Spans. +returned by the global TracerProvider will provide no-op functionality. This +means that all Span created prior to initialization are no-op Spans. Once an SDK has been initialized, all provided no-op Tracers are swapped for -Tracers provided by the SDK defined Provider. However, any Span started prior -to this initialization does not change its behavior. Meaning, the Span remains -a no-op Span. +Tracers provided by the SDK defined TracerProvider. However, any Span started +prior to this initialization does not change its behavior. Meaning, the Span +remains a no-op Span. The implementation to track and swap Tracers locks all new Tracer creation until the swap is complete. This assumes that this operation is not @@ -34,39 +34,43 @@ SDK prior to any Tracer creation. import ( "context" "sync" + "sync/atomic" - "go.opentelemetry.io/otel/api/trace" + "go.opentelemetry.io/otel/internal/trace/noop" + "go.opentelemetry.io/otel/trace" ) -// traceProvider is a placeholder for a configured SDK Provider. +// tracerProvider is a placeholder for a configured SDK TracerProvider. // -// All Provider functionality is forwarded to a delegate once configured. -type traceProvider struct { - mtx sync.Mutex - tracers []*tracer - - delegate trace.Provider +// All TracerProvider functionality is forwarded to a delegate once +// configured. +type tracerProvider struct { + mtx sync.Mutex + tracers map[il]*tracer + delegate trace.TracerProvider } -// Compile-time guarantee that traceProvider implements the trace.Provider interface. -var _ trace.Provider = &traceProvider{} +// Compile-time guarantee that tracerProvider implements the TracerProvider +// interface. +var _ trace.TracerProvider = &tracerProvider{} -// setDelegate configures p to delegate all Provider functionality to provider. +// setDelegate configures p to delegate all TracerProvider functionality to +// provider. // // All Tracers provided prior to this function call are switched out to be // Tracers provided by provider. // -// Delegation only happens on the first call to this method. All subsequent -// calls result in no delegation changes. -func (p *traceProvider) setDelegate(provider trace.Provider) { - if p.delegate != nil { - return - } - +// It is guaranteed by the caller that this happens only once. +func (p *tracerProvider) setDelegate(provider trace.TracerProvider) { p.mtx.Lock() defer p.mtx.Unlock() p.delegate = provider + + if len(p.tracers) == 0 { + return + } + for _, t := range p.tracers { t.setDelegate(provider) } @@ -74,30 +78,49 @@ func (p *traceProvider) setDelegate(provider trace.Provider) { p.tracers = nil } -// Tracer implements trace.Provider. -func (p *traceProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { +// Tracer implements TracerProvider. +func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { p.mtx.Lock() defer p.mtx.Unlock() if p.delegate != nil { - return p.delegate.Tracer(name) + return p.delegate.Tracer(name, opts...) + } + + // At this moment it is guaranteed that no sdk is installed, save the tracer in the tracers map. + + key := il{ + name: name, + version: trace.NewTracerConfig(opts...).InstrumentationVersion, + } + + if p.tracers == nil { + p.tracers = make(map[il]*tracer) + } + + if val, ok := p.tracers[key]; ok { + return val } t := &tracer{name: name, opts: opts} - p.tracers = append(p.tracers, t) + p.tracers[key] = t return t } +type il struct { + name string + version string +} + // tracer is a placeholder for a trace.Tracer. // // All Tracer functionality is forwarded to a delegate once configured. // Otherwise, all functionality is forwarded to a NoopTracer. type tracer struct { - once sync.Once name string opts []trace.TracerOption - delegate trace.Tracer + delegate atomic.Value } // Compile-time guarantee that tracer implements the trace.Tracer interface. @@ -108,17 +131,17 @@ var _ trace.Tracer = &tracer{} // // All subsequent calls to the Tracer methods will be passed to the delegate. // -// Delegation only happens on the first call to this method. All subsequent -// calls result in no delegation changes. -func (t *tracer) setDelegate(provider trace.Provider) { - t.once.Do(func() { t.delegate = provider.Tracer(t.name, t.opts...) }) +// It is guaranteed by the caller that this happens only once. +func (t *tracer) setDelegate(provider trace.TracerProvider) { + t.delegate.Store(provider.Tracer(t.name, t.opts...)) } // Start implements trace.Tracer by forwarding the call to t.delegate if // set, otherwise it forwards the call to a NoopTracer. -func (t *tracer) Start(ctx context.Context, name string, opts ...trace.StartOption) (context.Context, trace.Span) { - if t.delegate != nil { - return t.delegate.Start(ctx, name, opts...) +func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanOption) (context.Context, trace.Span) { + delegate := t.delegate.Load() + if delegate != nil { + return delegate.(trace.Tracer).Start(ctx, name, opts...) } - return trace.NoopTracer{}.Start(ctx, name, opts...) + return noop.Tracer.Start(ctx, name, opts...) } diff --git a/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go b/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go index dae825ed8b9d..0d806b1c8972 100644 --- a/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go +++ b/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go @@ -38,14 +38,6 @@ func RawToInt64(r uint64) int64 { return int64(r) } -func Uint64ToRaw(u uint64) uint64 { - return u -} - -func RawToUint64(r uint64) uint64 { - return r -} - func Float64ToRaw(f float64) uint64 { return math.Float64bits(f) } @@ -54,30 +46,6 @@ func RawToFloat64(r uint64) float64 { return math.Float64frombits(r) } -func Int32ToRaw(i int32) uint64 { - return uint64(i) -} - -func RawToInt32(r uint64) int32 { - return int32(r) -} - -func Uint32ToRaw(u uint32) uint64 { - return uint64(u) -} - -func RawToUint32(r uint64) uint32 { - return uint32(r) -} - -func Float32ToRaw(f float32) uint64 { - return Uint32ToRaw(math.Float32bits(f)) -} - -func RawToFloat32(r uint64) float32 { - return math.Float32frombits(RawToUint32(r)) -} - func RawPtrToFloat64Ptr(r *uint64) *float64 { return (*float64)(unsafe.Pointer(r)) } @@ -85,7 +53,3 @@ func RawPtrToFloat64Ptr(r *uint64) *float64 { func RawPtrToInt64Ptr(r *uint64) *int64 { return (*int64)(unsafe.Pointer(r)) } - -func RawPtrToUint64Ptr(r *uint64) *uint64 { - return r -} diff --git a/vendor/go.opentelemetry.io/otel/api/trace/noop_trace.go b/vendor/go.opentelemetry.io/otel/internal/trace/noop/noop.go similarity index 63% rename from vendor/go.opentelemetry.io/otel/api/trace/noop_trace.go rename to vendor/go.opentelemetry.io/otel/internal/trace/noop/noop.go index ffdb913185e4..765c21a289cb 100644 --- a/vendor/go.opentelemetry.io/otel/api/trace/noop_trace.go +++ b/vendor/go.opentelemetry.io/otel/internal/trace/noop/noop.go @@ -12,18 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -package trace +// Package noop provides noop tracing implementations for tracer and span. +package noop import ( "context" + + "go.opentelemetry.io/otel/trace" ) -type NoopTracer struct{} +var ( + // Tracer is a noop tracer that starts noop spans. + Tracer trace.Tracer -var _ Tracer = NoopTracer{} + // Span is a noop Span. + Span trace.Span +) -// Start starts a noop span. -func (NoopTracer) Start(ctx context.Context, name string, opts ...StartOption) (context.Context, Span) { - span := NoopSpan{} - return ContextWithSpan(ctx, span), span +func init() { + Tracer = trace.NewNoopTracerProvider().Tracer("") + _, Span = Tracer.Start(context.Background(), "") } diff --git a/vendor/go.opentelemetry.io/otel/metric/LICENSE b/vendor/go.opentelemetry.io/otel/metric/LICENSE new file mode 100644 index 000000000000..261eeb9e9f8b --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/metric/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/go.opentelemetry.io/otel/api/metric/config.go b/vendor/go.opentelemetry.io/otel/metric/config.go similarity index 80% rename from vendor/go.opentelemetry.io/otel/api/metric/config.go rename to vendor/go.opentelemetry.io/otel/metric/config.go index b5d45f9aeb9c..02f0ff8e0cb8 100644 --- a/vendor/go.opentelemetry.io/otel/api/metric/config.go +++ b/vendor/go.opentelemetry.io/otel/metric/config.go @@ -12,11 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package metric +package metric // import "go.opentelemetry.io/otel/metric" -import "go.opentelemetry.io/otel/api/unit" +import ( + "go.opentelemetry.io/otel/unit" +) -// InstrumentConfig contains options for instrument descriptors. +// InstrumentConfig contains options for metric instrument descriptors. type InstrumentConfig struct { // Description describes the instrument in human-readable terms. Description string @@ -30,16 +32,16 @@ type InstrumentConfig struct { InstrumentationVersion string } -// InstrumentOption is an interface for applying instrument options. +// InstrumentOption is an interface for applying metric instrument options. type InstrumentOption interface { // ApplyMeter is used to set a InstrumentOption value of a // InstrumentConfig. ApplyInstrument(*InstrumentConfig) } -// ConfigureInstrument is a helper that applies all the InstrumentOptions -// to an InstrumentConfig. -func ConfigureInstrument(opts []InstrumentOption) InstrumentConfig { +// NewInstrumentConfig creates a new InstrumentConfig +// and applies all the given options. +func NewInstrumentConfig(opts ...InstrumentOption) InstrumentConfig { var config InstrumentConfig for _, o := range opts { o.ApplyInstrument(&config) @@ -93,9 +95,9 @@ type MeterOption interface { ApplyMeter(*MeterConfig) } -// ConfigureMeter is a helper that applies all the MeterOptions to a -// MeterConfig. -func ConfigureMeter(opts []MeterOption) MeterConfig { +// NewMeterConfig creates a new MeterConfig and applies +// all the given options. +func NewMeterConfig(opts ...MeterOption) MeterConfig { var config MeterConfig for _, o := range opts { o.ApplyMeter(&config) @@ -103,14 +105,15 @@ func ConfigureMeter(opts []MeterOption) MeterConfig { return config } -// Option is an interface for applying Instrument or Meter options. -type Option interface { +// InstrumentationOption is an interface for applying instrumentation specific +// options. +type InstrumentationOption interface { InstrumentOption MeterOption } // WithInstrumentationVersion sets the instrumentation version. -func WithInstrumentationVersion(version string) Option { +func WithInstrumentationVersion(version string) InstrumentationOption { return instrumentationVersionOption(version) } diff --git a/vendor/go.opentelemetry.io/otel/metric/doc.go b/vendor/go.opentelemetry.io/otel/metric/doc.go new file mode 100644 index 000000000000..7889ff000f7c --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/metric/doc.go @@ -0,0 +1,67 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* +Package metric provides an implementation of the metrics part of the +OpenTelemetry API. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. + +Measurements can be made about an operation being performed or the state of a +system in general. These measurements can be crucial to the reliable operation +of code and provide valuable insights about the inner workings of a system. + +Measurements are made using instruments provided by this package. The type of +instrument used will depend on the type of measurement being made and of what +part of a system is being measured. + +Instruments are categorized as Synchronous or Asynchronous and independently +as Adding or Grouping. Synchronous instruments are called by the user with a +Context. Asynchronous instruments are called by the SDK during collection. +Additive instruments are semantically intended for capturing a sum. Grouping +instruments are intended for capturing a distribution. + +Additive instruments may be monotonic, in which case they are non-decreasing +and naturally define a rate. + +The synchronous instrument names are: + + Counter: additive, monotonic + UpDownCounter: additive + ValueRecorder: grouping + +and the asynchronous instruments are: + + SumObserver: additive, monotonic + UpDownSumObserver: additive + ValueObserver: grouping + +All instruments are provided with support for either float64 or int64 input +values. + +An instrument is created using a Meter. Additionally, a Meter is used to +record batches of synchronous measurements or asynchronous observations. A +Meter is obtained using a MeterProvider. A Meter, like a Tracer, is unique to +the instrumentation it instruments and must be named and versioned when +created with a MeterProvider with the name and version of the instrumentation +library. + +Instrumentation should be designed to accept a MeterProvider from which it can +create its own unique Meter. Alternatively, the registered global +MeterProvider from the go.opentelemetry.io/otel package can be used as a +default. +*/ +package metric // import "go.opentelemetry.io/otel/metric" diff --git a/vendor/go.opentelemetry.io/otel/api/global/metric.go b/vendor/go.opentelemetry.io/otel/metric/global/metric.go similarity index 74% rename from vendor/go.opentelemetry.io/otel/api/global/metric.go rename to vendor/go.opentelemetry.io/otel/metric/global/metric.go index 04409c46ea92..8d16d34d486e 100644 --- a/vendor/go.opentelemetry.io/otel/api/global/metric.go +++ b/vendor/go.opentelemetry.io/otel/metric/global/metric.go @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global +package global // import "go.opentelemetry.io/otel/metric/global" import ( - "go.opentelemetry.io/otel/api/global/internal" - "go.opentelemetry.io/otel/api/metric" + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/metric" ) // Meter creates an implementation of the Meter interface from the global -// Provider. The instrumentationName must be the name of the library +// MeterProvider. The instrumentationName must be the name of the library // providing instrumentation. This name may be the same as the instrumented // code only if that code provides built-in instrumentation. If the // instrumentationName is empty, then a implementation defined default name @@ -28,10 +28,10 @@ import ( // // This is short for MeterProvider().Meter(name) func Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { - return MeterProvider().Meter(instrumentationName, opts...) + return GetMeterProvider().Meter(instrumentationName, opts...) } -// MeterProvider returns the registered global meter provider. If +// GetMeterProvider returns the registered global meter provider. If // none is registered then a default meter provider is returned that // forwards the Meter interface to the first registered Meter. // @@ -39,11 +39,11 @@ func Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter // meter := global.MeterProvider().Meter("example.com/foo") // or // meter := global.Meter("example.com/foo") -func MeterProvider() metric.Provider { - return internal.MeterProvider() +func GetMeterProvider() metric.MeterProvider { + return global.MeterProvider() } // SetMeterProvider registers `mp` as the global meter provider. -func SetMeterProvider(mp metric.Provider) { - internal.SetMeterProvider(mp) +func SetMeterProvider(mp metric.MeterProvider) { + global.SetMeterProvider(mp) } diff --git a/vendor/go.opentelemetry.io/otel/metric/go.mod b/vendor/go.opentelemetry.io/otel/metric/go.mod new file mode 100644 index 000000000000..47bc47badde6 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/metric/go.mod @@ -0,0 +1,54 @@ +module go.opentelemetry.io/otel/metric + +go 1.14 + +replace go.opentelemetry.io/otel => ../ + +replace go.opentelemetry.io/otel/bridge/opencensus => ../bridge/opencensus + +replace go.opentelemetry.io/otel/bridge/opentracing => ../bridge/opentracing + +replace go.opentelemetry.io/otel/example/jaeger => ../example/jaeger + +replace go.opentelemetry.io/otel/example/namedtracer => ../example/namedtracer + +replace go.opentelemetry.io/otel/example/opencensus => ../example/opencensus + +replace go.opentelemetry.io/otel/example/otel-collector => ../example/otel-collector + +replace go.opentelemetry.io/otel/example/prom-collector => ../example/prom-collector + +replace go.opentelemetry.io/otel/example/prometheus => ../example/prometheus + +replace go.opentelemetry.io/otel/example/zipkin => ../example/zipkin + +replace go.opentelemetry.io/otel/exporters/metric/prometheus => ../exporters/metric/prometheus + +replace go.opentelemetry.io/otel/exporters/otlp => ../exporters/otlp + +replace go.opentelemetry.io/otel/exporters/stdout => ../exporters/stdout + +replace go.opentelemetry.io/otel/exporters/trace/jaeger => ../exporters/trace/jaeger + +replace go.opentelemetry.io/otel/exporters/trace/zipkin => ../exporters/trace/zipkin + +replace go.opentelemetry.io/otel/internal/tools => ../internal/tools + +replace go.opentelemetry.io/otel/metric => ./ + +replace go.opentelemetry.io/otel/oteltest => ../oteltest + +replace go.opentelemetry.io/otel/sdk => ../sdk + +replace go.opentelemetry.io/otel/sdk/export/metric => ../sdk/export/metric + +replace go.opentelemetry.io/otel/sdk/metric => ../sdk/metric + +replace go.opentelemetry.io/otel/trace => ../trace + +require ( + github.com/google/go-cmp v0.5.5 + github.com/stretchr/testify v1.7.0 + go.opentelemetry.io/otel v0.20.0 + go.opentelemetry.io/otel/oteltest v0.20.0 +) diff --git a/vendor/go.opentelemetry.io/otel/metric/go.sum b/vendor/go.opentelemetry.io/otel/metric/go.sum new file mode 100644 index 000000000000..b69f2e56da0f --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/metric/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/go.opentelemetry.io/otel/metric/instrumentkind_string.go b/vendor/go.opentelemetry.io/otel/metric/instrumentkind_string.go new file mode 100644 index 000000000000..2805e22500c7 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/metric/instrumentkind_string.go @@ -0,0 +1,28 @@ +// Code generated by "stringer -type=InstrumentKind"; DO NOT EDIT. + +package metric + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[ValueRecorderInstrumentKind-0] + _ = x[ValueObserverInstrumentKind-1] + _ = x[CounterInstrumentKind-2] + _ = x[UpDownCounterInstrumentKind-3] + _ = x[SumObserverInstrumentKind-4] + _ = x[UpDownSumObserverInstrumentKind-5] +} + +const _InstrumentKind_name = "ValueRecorderInstrumentKindValueObserverInstrumentKindCounterInstrumentKindUpDownCounterInstrumentKindSumObserverInstrumentKindUpDownSumObserverInstrumentKind" + +var _InstrumentKind_index = [...]uint8{0, 27, 54, 75, 102, 127, 158} + +func (i InstrumentKind) String() string { + if i < 0 || i >= InstrumentKind(len(_InstrumentKind_index)-1) { + return "InstrumentKind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _InstrumentKind_name[_InstrumentKind_index[i]:_InstrumentKind_index[i+1]] +} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/meter.go b/vendor/go.opentelemetry.io/otel/metric/metric.go similarity index 50% rename from vendor/go.opentelemetry.io/otel/api/metric/meter.go rename to vendor/go.opentelemetry.io/otel/metric/metric.go index 079c294776fa..b591985df686 100644 --- a/vendor/go.opentelemetry.io/otel/api/metric/meter.go +++ b/vendor/go.opentelemetry.io/otel/metric/metric.go @@ -12,27 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package metric +package metric // import "go.opentelemetry.io/otel/metric" import ( "context" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/number" + "go.opentelemetry.io/otel/unit" ) -// The file is organized as follows: -// -// - Provider interface -// - Meter struct -// - RecordBatch -// - BatchObserver -// - Synchronous instrument constructors (2 x int64,float64) -// - Asynchronous instrument constructors (1 x int64,float64) -// - Batch asynchronous constructors (1 x int64,float64) -// - Internals - -// Provider supports named Meter instances. -type Provider interface { +// MeterProvider supports named Meter instances. +type MeterProvider interface { // Meter creates an implementation of the Meter interface. // The instrumentationName must be the name of the library providing // instrumentation. This name may be the same as the instrumented code @@ -42,8 +33,7 @@ type Provider interface { Meter(instrumentationName string, opts ...MeterOption) Meter } -// Meter is the OpenTelemetry metric API, based on a `MeterImpl` -// implementation and the `Meter` library name. +// Meter is the creator of metric instruments. // // An uninitialized Meter is a no-op implementation. type Meter struct { @@ -52,7 +42,7 @@ type Meter struct { } // RecordBatch atomically records a batch of measurements. -func (m Meter) RecordBatch(ctx context.Context, ls []label.KeyValue, ms ...Measurement) { +func (m Meter) RecordBatch(ctx context.Context, ls []attribute.KeyValue, ms ...Measurement) { if m.impl == nil { return } @@ -74,7 +64,7 @@ func (m Meter) NewBatchObserver(callback BatchObserverFunc) BatchObserver { // duplicate registration). func (m Meter) NewInt64Counter(name string, options ...InstrumentOption) (Int64Counter, error) { return wrapInt64CounterInstrument( - m.newSync(name, CounterKind, Int64NumberKind, options)) + m.newSync(name, CounterInstrumentKind, number.Int64Kind, options)) } // NewFloat64Counter creates a new floating point Counter with the @@ -83,7 +73,7 @@ func (m Meter) NewInt64Counter(name string, options ...InstrumentOption) (Int64C // duplicate registration). func (m Meter) NewFloat64Counter(name string, options ...InstrumentOption) (Float64Counter, error) { return wrapFloat64CounterInstrument( - m.newSync(name, CounterKind, Float64NumberKind, options)) + m.newSync(name, CounterInstrumentKind, number.Float64Kind, options)) } // NewInt64UpDownCounter creates a new integer UpDownCounter instrument with the @@ -92,7 +82,7 @@ func (m Meter) NewFloat64Counter(name string, options ...InstrumentOption) (Floa // duplicate registration). func (m Meter) NewInt64UpDownCounter(name string, options ...InstrumentOption) (Int64UpDownCounter, error) { return wrapInt64UpDownCounterInstrument( - m.newSync(name, UpDownCounterKind, Int64NumberKind, options)) + m.newSync(name, UpDownCounterInstrumentKind, number.Int64Kind, options)) } // NewFloat64UpDownCounter creates a new floating point UpDownCounter with the @@ -101,7 +91,7 @@ func (m Meter) NewInt64UpDownCounter(name string, options ...InstrumentOption) ( // duplicate registration). func (m Meter) NewFloat64UpDownCounter(name string, options ...InstrumentOption) (Float64UpDownCounter, error) { return wrapFloat64UpDownCounterInstrument( - m.newSync(name, UpDownCounterKind, Float64NumberKind, options)) + m.newSync(name, UpDownCounterInstrumentKind, number.Float64Kind, options)) } // NewInt64ValueRecorder creates a new integer ValueRecorder instrument with the @@ -110,7 +100,7 @@ func (m Meter) NewFloat64UpDownCounter(name string, options ...InstrumentOption) // duplicate registration). func (m Meter) NewInt64ValueRecorder(name string, opts ...InstrumentOption) (Int64ValueRecorder, error) { return wrapInt64ValueRecorderInstrument( - m.newSync(name, ValueRecorderKind, Int64NumberKind, opts)) + m.newSync(name, ValueRecorderInstrumentKind, number.Int64Kind, opts)) } // NewFloat64ValueRecorder creates a new floating point ValueRecorder with the @@ -119,7 +109,7 @@ func (m Meter) NewInt64ValueRecorder(name string, opts ...InstrumentOption) (Int // duplicate registration). func (m Meter) NewFloat64ValueRecorder(name string, opts ...InstrumentOption) (Float64ValueRecorder, error) { return wrapFloat64ValueRecorderInstrument( - m.newSync(name, ValueRecorderKind, Float64NumberKind, opts)) + m.newSync(name, ValueRecorderInstrumentKind, number.Float64Kind, opts)) } // NewInt64ValueObserver creates a new integer ValueObserver instrument @@ -131,7 +121,7 @@ func (m Meter) NewInt64ValueObserver(name string, callback Int64ObserverFunc, op return wrapInt64ValueObserverInstrument(NoopAsync{}, nil) } return wrapInt64ValueObserverInstrument( - m.newAsync(name, ValueObserverKind, Int64NumberKind, opts, + m.newAsync(name, ValueObserverInstrumentKind, number.Int64Kind, opts, newInt64AsyncRunner(callback))) } @@ -144,7 +134,7 @@ func (m Meter) NewFloat64ValueObserver(name string, callback Float64ObserverFunc return wrapFloat64ValueObserverInstrument(NoopAsync{}, nil) } return wrapFloat64ValueObserverInstrument( - m.newAsync(name, ValueObserverKind, Float64NumberKind, opts, + m.newAsync(name, ValueObserverInstrumentKind, number.Float64Kind, opts, newFloat64AsyncRunner(callback))) } @@ -157,7 +147,7 @@ func (m Meter) NewInt64SumObserver(name string, callback Int64ObserverFunc, opts return wrapInt64SumObserverInstrument(NoopAsync{}, nil) } return wrapInt64SumObserverInstrument( - m.newAsync(name, SumObserverKind, Int64NumberKind, opts, + m.newAsync(name, SumObserverInstrumentKind, number.Int64Kind, opts, newInt64AsyncRunner(callback))) } @@ -170,7 +160,7 @@ func (m Meter) NewFloat64SumObserver(name string, callback Float64ObserverFunc, return wrapFloat64SumObserverInstrument(NoopAsync{}, nil) } return wrapFloat64SumObserverInstrument( - m.newAsync(name, SumObserverKind, Float64NumberKind, opts, + m.newAsync(name, SumObserverInstrumentKind, number.Float64Kind, opts, newFloat64AsyncRunner(callback))) } @@ -183,7 +173,7 @@ func (m Meter) NewInt64UpDownSumObserver(name string, callback Int64ObserverFunc return wrapInt64UpDownSumObserverInstrument(NoopAsync{}, nil) } return wrapInt64UpDownSumObserverInstrument( - m.newAsync(name, UpDownSumObserverKind, Int64NumberKind, opts, + m.newAsync(name, UpDownSumObserverInstrumentKind, number.Int64Kind, opts, newInt64AsyncRunner(callback))) } @@ -196,7 +186,7 @@ func (m Meter) NewFloat64UpDownSumObserver(name string, callback Float64Observer return wrapFloat64UpDownSumObserverInstrument(NoopAsync{}, nil) } return wrapFloat64UpDownSumObserverInstrument( - m.newAsync(name, UpDownSumObserverKind, Float64NumberKind, opts, + m.newAsync(name, UpDownSumObserverInstrumentKind, number.Float64Kind, opts, newFloat64AsyncRunner(callback))) } @@ -209,7 +199,7 @@ func (b BatchObserver) NewInt64ValueObserver(name string, opts ...InstrumentOpti return wrapInt64ValueObserverInstrument(NoopAsync{}, nil) } return wrapInt64ValueObserverInstrument( - b.meter.newAsync(name, ValueObserverKind, Int64NumberKind, opts, b.runner)) + b.meter.newAsync(name, ValueObserverInstrumentKind, number.Int64Kind, opts, b.runner)) } // NewFloat64ValueObserver creates a new floating point ValueObserver with @@ -221,7 +211,7 @@ func (b BatchObserver) NewFloat64ValueObserver(name string, opts ...InstrumentOp return wrapFloat64ValueObserverInstrument(NoopAsync{}, nil) } return wrapFloat64ValueObserverInstrument( - b.meter.newAsync(name, ValueObserverKind, Float64NumberKind, opts, + b.meter.newAsync(name, ValueObserverInstrumentKind, number.Float64Kind, opts, b.runner)) } @@ -234,7 +224,7 @@ func (b BatchObserver) NewInt64SumObserver(name string, opts ...InstrumentOption return wrapInt64SumObserverInstrument(NoopAsync{}, nil) } return wrapInt64SumObserverInstrument( - b.meter.newAsync(name, SumObserverKind, Int64NumberKind, opts, b.runner)) + b.meter.newAsync(name, SumObserverInstrumentKind, number.Int64Kind, opts, b.runner)) } // NewFloat64SumObserver creates a new floating point SumObserver with @@ -246,7 +236,7 @@ func (b BatchObserver) NewFloat64SumObserver(name string, opts ...InstrumentOpti return wrapFloat64SumObserverInstrument(NoopAsync{}, nil) } return wrapFloat64SumObserverInstrument( - b.meter.newAsync(name, SumObserverKind, Float64NumberKind, opts, + b.meter.newAsync(name, SumObserverInstrumentKind, number.Float64Kind, opts, b.runner)) } @@ -259,7 +249,7 @@ func (b BatchObserver) NewInt64UpDownSumObserver(name string, opts ...Instrument return wrapInt64UpDownSumObserverInstrument(NoopAsync{}, nil) } return wrapInt64UpDownSumObserverInstrument( - b.meter.newAsync(name, UpDownSumObserverKind, Int64NumberKind, opts, b.runner)) + b.meter.newAsync(name, UpDownSumObserverInstrumentKind, number.Int64Kind, opts, b.runner)) } // NewFloat64UpDownSumObserver creates a new floating point UpDownSumObserver with @@ -271,7 +261,7 @@ func (b BatchObserver) NewFloat64UpDownSumObserver(name string, opts ...Instrume return wrapFloat64UpDownSumObserverInstrument(NoopAsync{}, nil) } return wrapFloat64UpDownSumObserverInstrument( - b.meter.newAsync(name, UpDownSumObserverKind, Float64NumberKind, opts, + b.meter.newAsync(name, UpDownSumObserverInstrumentKind, number.Float64Kind, opts, b.runner)) } @@ -283,8 +273,8 @@ func (m Meter) MeterImpl() MeterImpl { // newAsync constructs one new asynchronous instrument. func (m Meter) newAsync( name string, - mkind Kind, - nkind NumberKind, + mkind InstrumentKind, + nkind number.Kind, opts []InstrumentOption, runner AsyncRunner, ) ( @@ -303,8 +293,8 @@ func (m Meter) newAsync( // newSync constructs one new synchronous instrument. func (m Meter) newSync( name string, - metricKind Kind, - numberKind NumberKind, + metricKind InstrumentKind, + numberKind number.Kind, opts []InstrumentOption, ) ( SyncImpl, @@ -318,3 +308,270 @@ func (m Meter) newSync( desc.config.InstrumentationVersion = m.version return m.impl.NewSyncInstrument(desc) } + +// MeterMust is a wrapper for Meter interfaces that panics when any +// instrument constructor encounters an error. +type MeterMust struct { + meter Meter +} + +// BatchObserverMust is a wrapper for BatchObserver that panics when +// any instrument constructor encounters an error. +type BatchObserverMust struct { + batch BatchObserver +} + +// Must constructs a MeterMust implementation from a Meter, allowing +// the application to panic when any instrument constructor yields an +// error. +func Must(meter Meter) MeterMust { + return MeterMust{meter: meter} +} + +// NewInt64Counter calls `Meter.NewInt64Counter` and returns the +// instrument, panicking if it encounters an error. +func (mm MeterMust) NewInt64Counter(name string, cos ...InstrumentOption) Int64Counter { + if inst, err := mm.meter.NewInt64Counter(name, cos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64Counter calls `Meter.NewFloat64Counter` and returns the +// instrument, panicking if it encounters an error. +func (mm MeterMust) NewFloat64Counter(name string, cos ...InstrumentOption) Float64Counter { + if inst, err := mm.meter.NewFloat64Counter(name, cos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewInt64UpDownCounter calls `Meter.NewInt64UpDownCounter` and returns the +// instrument, panicking if it encounters an error. +func (mm MeterMust) NewInt64UpDownCounter(name string, cos ...InstrumentOption) Int64UpDownCounter { + if inst, err := mm.meter.NewInt64UpDownCounter(name, cos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64UpDownCounter calls `Meter.NewFloat64UpDownCounter` and returns the +// instrument, panicking if it encounters an error. +func (mm MeterMust) NewFloat64UpDownCounter(name string, cos ...InstrumentOption) Float64UpDownCounter { + if inst, err := mm.meter.NewFloat64UpDownCounter(name, cos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewInt64ValueRecorder calls `Meter.NewInt64ValueRecorder` and returns the +// instrument, panicking if it encounters an error. +func (mm MeterMust) NewInt64ValueRecorder(name string, mos ...InstrumentOption) Int64ValueRecorder { + if inst, err := mm.meter.NewInt64ValueRecorder(name, mos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64ValueRecorder calls `Meter.NewFloat64ValueRecorder` and returns the +// instrument, panicking if it encounters an error. +func (mm MeterMust) NewFloat64ValueRecorder(name string, mos ...InstrumentOption) Float64ValueRecorder { + if inst, err := mm.meter.NewFloat64ValueRecorder(name, mos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewInt64ValueObserver calls `Meter.NewInt64ValueObserver` and +// returns the instrument, panicking if it encounters an error. +func (mm MeterMust) NewInt64ValueObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64ValueObserver { + if inst, err := mm.meter.NewInt64ValueObserver(name, callback, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64ValueObserver calls `Meter.NewFloat64ValueObserver` and +// returns the instrument, panicking if it encounters an error. +func (mm MeterMust) NewFloat64ValueObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64ValueObserver { + if inst, err := mm.meter.NewFloat64ValueObserver(name, callback, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewInt64SumObserver calls `Meter.NewInt64SumObserver` and +// returns the instrument, panicking if it encounters an error. +func (mm MeterMust) NewInt64SumObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64SumObserver { + if inst, err := mm.meter.NewInt64SumObserver(name, callback, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64SumObserver calls `Meter.NewFloat64SumObserver` and +// returns the instrument, panicking if it encounters an error. +func (mm MeterMust) NewFloat64SumObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64SumObserver { + if inst, err := mm.meter.NewFloat64SumObserver(name, callback, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewInt64UpDownSumObserver calls `Meter.NewInt64UpDownSumObserver` and +// returns the instrument, panicking if it encounters an error. +func (mm MeterMust) NewInt64UpDownSumObserver(name string, callback Int64ObserverFunc, oos ...InstrumentOption) Int64UpDownSumObserver { + if inst, err := mm.meter.NewInt64UpDownSumObserver(name, callback, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64UpDownSumObserver calls `Meter.NewFloat64UpDownSumObserver` and +// returns the instrument, panicking if it encounters an error. +func (mm MeterMust) NewFloat64UpDownSumObserver(name string, callback Float64ObserverFunc, oos ...InstrumentOption) Float64UpDownSumObserver { + if inst, err := mm.meter.NewFloat64UpDownSumObserver(name, callback, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewBatchObserver returns a wrapper around BatchObserver that panics +// when any instrument constructor returns an error. +func (mm MeterMust) NewBatchObserver(callback BatchObserverFunc) BatchObserverMust { + return BatchObserverMust{ + batch: mm.meter.NewBatchObserver(callback), + } +} + +// NewInt64ValueObserver calls `BatchObserver.NewInt64ValueObserver` and +// returns the instrument, panicking if it encounters an error. +func (bm BatchObserverMust) NewInt64ValueObserver(name string, oos ...InstrumentOption) Int64ValueObserver { + if inst, err := bm.batch.NewInt64ValueObserver(name, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64ValueObserver calls `BatchObserver.NewFloat64ValueObserver` and +// returns the instrument, panicking if it encounters an error. +func (bm BatchObserverMust) NewFloat64ValueObserver(name string, oos ...InstrumentOption) Float64ValueObserver { + if inst, err := bm.batch.NewFloat64ValueObserver(name, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewInt64SumObserver calls `BatchObserver.NewInt64SumObserver` and +// returns the instrument, panicking if it encounters an error. +func (bm BatchObserverMust) NewInt64SumObserver(name string, oos ...InstrumentOption) Int64SumObserver { + if inst, err := bm.batch.NewInt64SumObserver(name, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64SumObserver calls `BatchObserver.NewFloat64SumObserver` and +// returns the instrument, panicking if it encounters an error. +func (bm BatchObserverMust) NewFloat64SumObserver(name string, oos ...InstrumentOption) Float64SumObserver { + if inst, err := bm.batch.NewFloat64SumObserver(name, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewInt64UpDownSumObserver calls `BatchObserver.NewInt64UpDownSumObserver` and +// returns the instrument, panicking if it encounters an error. +func (bm BatchObserverMust) NewInt64UpDownSumObserver(name string, oos ...InstrumentOption) Int64UpDownSumObserver { + if inst, err := bm.batch.NewInt64UpDownSumObserver(name, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// NewFloat64UpDownSumObserver calls `BatchObserver.NewFloat64UpDownSumObserver` and +// returns the instrument, panicking if it encounters an error. +func (bm BatchObserverMust) NewFloat64UpDownSumObserver(name string, oos ...InstrumentOption) Float64UpDownSumObserver { + if inst, err := bm.batch.NewFloat64UpDownSumObserver(name, oos...); err != nil { + panic(err) + } else { + return inst + } +} + +// Descriptor contains all the settings that describe an instrument, +// including its name, metric kind, number kind, and the configurable +// options. +type Descriptor struct { + name string + instrumentKind InstrumentKind + numberKind number.Kind + config InstrumentConfig +} + +// NewDescriptor returns a Descriptor with the given contents. +func NewDescriptor(name string, ikind InstrumentKind, nkind number.Kind, opts ...InstrumentOption) Descriptor { + return Descriptor{ + name: name, + instrumentKind: ikind, + numberKind: nkind, + config: NewInstrumentConfig(opts...), + } +} + +// Name returns the metric instrument's name. +func (d Descriptor) Name() string { + return d.name +} + +// InstrumentKind returns the specific kind of instrument. +func (d Descriptor) InstrumentKind() InstrumentKind { + return d.instrumentKind +} + +// Description provides a human-readable description of the metric +// instrument. +func (d Descriptor) Description() string { + return d.config.Description +} + +// Unit describes the units of the metric instrument. Unitless +// metrics return the empty string. +func (d Descriptor) Unit() unit.Unit { + return d.config.Unit +} + +// NumberKind returns whether this instrument is declared over int64, +// float64, or uint64 values. +func (d Descriptor) NumberKind() number.Kind { + return d.numberKind +} + +// InstrumentationName returns the name of the library that provided +// instrumentation for this instrument. +func (d Descriptor) InstrumentationName() string { + return d.config.InstrumentationName +} + +// InstrumentationVersion returns the version of the library that provided +// instrumentation for this instrument. +func (d Descriptor) InstrumentationVersion() string { + return d.config.InstrumentationVersion +} diff --git a/vendor/go.opentelemetry.io/otel/metric/metric_instrument.go b/vendor/go.opentelemetry.io/otel/metric/metric_instrument.go new file mode 100644 index 000000000000..6f3fc997cb9f --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/metric/metric_instrument.go @@ -0,0 +1,777 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate stringer -type=InstrumentKind + +package metric // import "go.opentelemetry.io/otel/metric" + +import ( + "context" + "errors" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/number" +) + +// ErrSDKReturnedNilImpl is returned when a new `MeterImpl` returns nil. +var ErrSDKReturnedNilImpl = errors.New("SDK returned a nil implementation") + +// InstrumentKind describes the kind of instrument. +type InstrumentKind int8 + +const ( + // ValueRecorderInstrumentKind indicates a ValueRecorder instrument. + ValueRecorderInstrumentKind InstrumentKind = iota + // ValueObserverInstrumentKind indicates an ValueObserver instrument. + ValueObserverInstrumentKind + + // CounterInstrumentKind indicates a Counter instrument. + CounterInstrumentKind + // UpDownCounterInstrumentKind indicates a UpDownCounter instrument. + UpDownCounterInstrumentKind + + // SumObserverInstrumentKind indicates a SumObserver instrument. + SumObserverInstrumentKind + // UpDownSumObserverInstrumentKind indicates a UpDownSumObserver + // instrument. + UpDownSumObserverInstrumentKind +) + +// Synchronous returns whether this is a synchronous kind of instrument. +func (k InstrumentKind) Synchronous() bool { + switch k { + case CounterInstrumentKind, UpDownCounterInstrumentKind, ValueRecorderInstrumentKind: + return true + } + return false +} + +// Asynchronous returns whether this is an asynchronous kind of instrument. +func (k InstrumentKind) Asynchronous() bool { + return !k.Synchronous() +} + +// Adding returns whether this kind of instrument adds its inputs (as opposed to Grouping). +func (k InstrumentKind) Adding() bool { + switch k { + case CounterInstrumentKind, UpDownCounterInstrumentKind, SumObserverInstrumentKind, UpDownSumObserverInstrumentKind: + return true + } + return false +} + +// Grouping returns whether this kind of instrument groups its inputs (as opposed to Adding). +func (k InstrumentKind) Grouping() bool { + return !k.Adding() +} + +// Monotonic returns whether this kind of instrument exposes a non-decreasing sum. +func (k InstrumentKind) Monotonic() bool { + switch k { + case CounterInstrumentKind, SumObserverInstrumentKind: + return true + } + return false +} + +// PrecomputedSum returns whether this kind of instrument receives precomputed sums. +func (k InstrumentKind) PrecomputedSum() bool { + return k.Adding() && k.Asynchronous() +} + +// Observation is used for reporting an asynchronous batch of metric +// values. Instances of this type should be created by asynchronous +// instruments (e.g., Int64ValueObserver.Observation()). +type Observation struct { + // number needs to be aligned for 64-bit atomic operations. + number number.Number + instrument AsyncImpl +} + +// Int64ObserverFunc is a type of callback that integral +// observers run. +type Int64ObserverFunc func(context.Context, Int64ObserverResult) + +// Float64ObserverFunc is a type of callback that floating point +// observers run. +type Float64ObserverFunc func(context.Context, Float64ObserverResult) + +// BatchObserverFunc is a callback argument for use with any +// Observer instrument that will be reported as a batch of +// observations. +type BatchObserverFunc func(context.Context, BatchObserverResult) + +// Int64ObserverResult is passed to an observer callback to capture +// observations for one asynchronous integer metric instrument. +type Int64ObserverResult struct { + instrument AsyncImpl + function func([]attribute.KeyValue, ...Observation) +} + +// Float64ObserverResult is passed to an observer callback to capture +// observations for one asynchronous floating point metric instrument. +type Float64ObserverResult struct { + instrument AsyncImpl + function func([]attribute.KeyValue, ...Observation) +} + +// BatchObserverResult is passed to a batch observer callback to +// capture observations for multiple asynchronous instruments. +type BatchObserverResult struct { + function func([]attribute.KeyValue, ...Observation) +} + +// Observe captures a single integer value from the associated +// instrument callback, with the given labels. +func (ir Int64ObserverResult) Observe(value int64, labels ...attribute.KeyValue) { + ir.function(labels, Observation{ + instrument: ir.instrument, + number: number.NewInt64Number(value), + }) +} + +// Observe captures a single floating point value from the associated +// instrument callback, with the given labels. +func (fr Float64ObserverResult) Observe(value float64, labels ...attribute.KeyValue) { + fr.function(labels, Observation{ + instrument: fr.instrument, + number: number.NewFloat64Number(value), + }) +} + +// Observe captures a multiple observations from the associated batch +// instrument callback, with the given labels. +func (br BatchObserverResult) Observe(labels []attribute.KeyValue, obs ...Observation) { + br.function(labels, obs...) +} + +// AsyncRunner is expected to convert into an AsyncSingleRunner or an +// AsyncBatchRunner. SDKs will encounter an error if the AsyncRunner +// does not satisfy one of these interfaces. +type AsyncRunner interface { + // AnyRunner() is a non-exported method with no functional use + // other than to make this a non-empty interface. + AnyRunner() +} + +// AsyncSingleRunner is an interface implemented by single-observer +// callbacks. +type AsyncSingleRunner interface { + // Run accepts a single instrument and function for capturing + // observations of that instrument. Each call to the function + // receives one captured observation. (The function accepts + // multiple observations so the same implementation can be + // used for batch runners.) + Run(ctx context.Context, single AsyncImpl, capture func([]attribute.KeyValue, ...Observation)) + + AsyncRunner +} + +// AsyncBatchRunner is an interface implemented by batch-observer +// callbacks. +type AsyncBatchRunner interface { + // Run accepts a function for capturing observations of + // multiple instruments. + Run(ctx context.Context, capture func([]attribute.KeyValue, ...Observation)) + + AsyncRunner +} + +var _ AsyncSingleRunner = (*Int64ObserverFunc)(nil) +var _ AsyncSingleRunner = (*Float64ObserverFunc)(nil) +var _ AsyncBatchRunner = (*BatchObserverFunc)(nil) + +// newInt64AsyncRunner returns a single-observer callback for integer Observer instruments. +func newInt64AsyncRunner(c Int64ObserverFunc) AsyncSingleRunner { + return &c +} + +// newFloat64AsyncRunner returns a single-observer callback for floating point Observer instruments. +func newFloat64AsyncRunner(c Float64ObserverFunc) AsyncSingleRunner { + return &c +} + +// newBatchAsyncRunner returns a batch-observer callback use with multiple Observer instruments. +func newBatchAsyncRunner(c BatchObserverFunc) AsyncBatchRunner { + return &c +} + +// AnyRunner implements AsyncRunner. +func (*Int64ObserverFunc) AnyRunner() {} + +// AnyRunner implements AsyncRunner. +func (*Float64ObserverFunc) AnyRunner() {} + +// AnyRunner implements AsyncRunner. +func (*BatchObserverFunc) AnyRunner() {} + +// Run implements AsyncSingleRunner. +func (i *Int64ObserverFunc) Run(ctx context.Context, impl AsyncImpl, function func([]attribute.KeyValue, ...Observation)) { + (*i)(ctx, Int64ObserverResult{ + instrument: impl, + function: function, + }) +} + +// Run implements AsyncSingleRunner. +func (f *Float64ObserverFunc) Run(ctx context.Context, impl AsyncImpl, function func([]attribute.KeyValue, ...Observation)) { + (*f)(ctx, Float64ObserverResult{ + instrument: impl, + function: function, + }) +} + +// Run implements AsyncBatchRunner. +func (b *BatchObserverFunc) Run(ctx context.Context, function func([]attribute.KeyValue, ...Observation)) { + (*b)(ctx, BatchObserverResult{ + function: function, + }) +} + +// wrapInt64ValueObserverInstrument converts an AsyncImpl into Int64ValueObserver. +func wrapInt64ValueObserverInstrument(asyncInst AsyncImpl, err error) (Int64ValueObserver, error) { + common, err := checkNewAsync(asyncInst, err) + return Int64ValueObserver{asyncInstrument: common}, err +} + +// wrapFloat64ValueObserverInstrument converts an AsyncImpl into Float64ValueObserver. +func wrapFloat64ValueObserverInstrument(asyncInst AsyncImpl, err error) (Float64ValueObserver, error) { + common, err := checkNewAsync(asyncInst, err) + return Float64ValueObserver{asyncInstrument: common}, err +} + +// wrapInt64SumObserverInstrument converts an AsyncImpl into Int64SumObserver. +func wrapInt64SumObserverInstrument(asyncInst AsyncImpl, err error) (Int64SumObserver, error) { + common, err := checkNewAsync(asyncInst, err) + return Int64SumObserver{asyncInstrument: common}, err +} + +// wrapFloat64SumObserverInstrument converts an AsyncImpl into Float64SumObserver. +func wrapFloat64SumObserverInstrument(asyncInst AsyncImpl, err error) (Float64SumObserver, error) { + common, err := checkNewAsync(asyncInst, err) + return Float64SumObserver{asyncInstrument: common}, err +} + +// wrapInt64UpDownSumObserverInstrument converts an AsyncImpl into Int64UpDownSumObserver. +func wrapInt64UpDownSumObserverInstrument(asyncInst AsyncImpl, err error) (Int64UpDownSumObserver, error) { + common, err := checkNewAsync(asyncInst, err) + return Int64UpDownSumObserver{asyncInstrument: common}, err +} + +// wrapFloat64UpDownSumObserverInstrument converts an AsyncImpl into Float64UpDownSumObserver. +func wrapFloat64UpDownSumObserverInstrument(asyncInst AsyncImpl, err error) (Float64UpDownSumObserver, error) { + common, err := checkNewAsync(asyncInst, err) + return Float64UpDownSumObserver{asyncInstrument: common}, err +} + +// BatchObserver represents an Observer callback that can report +// observations for multiple instruments. +type BatchObserver struct { + meter Meter + runner AsyncBatchRunner +} + +// Int64ValueObserver is a metric that captures a set of int64 values at a +// point in time. +type Int64ValueObserver struct { + asyncInstrument +} + +// Float64ValueObserver is a metric that captures a set of float64 values +// at a point in time. +type Float64ValueObserver struct { + asyncInstrument +} + +// Int64SumObserver is a metric that captures a precomputed sum of +// int64 values at a point in time. +type Int64SumObserver struct { + asyncInstrument +} + +// Float64SumObserver is a metric that captures a precomputed sum of +// float64 values at a point in time. +type Float64SumObserver struct { + asyncInstrument +} + +// Int64UpDownSumObserver is a metric that captures a precomputed sum of +// int64 values at a point in time. +type Int64UpDownSumObserver struct { + asyncInstrument +} + +// Float64UpDownSumObserver is a metric that captures a precomputed sum of +// float64 values at a point in time. +type Float64UpDownSumObserver struct { + asyncInstrument +} + +// Observation returns an Observation, a BatchObserverFunc +// argument, for an asynchronous integer instrument. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (i Int64ValueObserver) Observation(v int64) Observation { + return Observation{ + number: number.NewInt64Number(v), + instrument: i.instrument, + } +} + +// Observation returns an Observation, a BatchObserverFunc +// argument, for an asynchronous integer instrument. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (f Float64ValueObserver) Observation(v float64) Observation { + return Observation{ + number: number.NewFloat64Number(v), + instrument: f.instrument, + } +} + +// Observation returns an Observation, a BatchObserverFunc +// argument, for an asynchronous integer instrument. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (i Int64SumObserver) Observation(v int64) Observation { + return Observation{ + number: number.NewInt64Number(v), + instrument: i.instrument, + } +} + +// Observation returns an Observation, a BatchObserverFunc +// argument, for an asynchronous integer instrument. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (f Float64SumObserver) Observation(v float64) Observation { + return Observation{ + number: number.NewFloat64Number(v), + instrument: f.instrument, + } +} + +// Observation returns an Observation, a BatchObserverFunc +// argument, for an asynchronous integer instrument. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (i Int64UpDownSumObserver) Observation(v int64) Observation { + return Observation{ + number: number.NewInt64Number(v), + instrument: i.instrument, + } +} + +// Observation returns an Observation, a BatchObserverFunc +// argument, for an asynchronous integer instrument. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (f Float64UpDownSumObserver) Observation(v float64) Observation { + return Observation{ + number: number.NewFloat64Number(v), + instrument: f.instrument, + } +} + +// Measurement is used for reporting a synchronous batch of metric +// values. Instances of this type should be created by synchronous +// instruments (e.g., Int64Counter.Measurement()). +type Measurement struct { + // number needs to be aligned for 64-bit atomic operations. + number number.Number + instrument SyncImpl +} + +// syncInstrument contains a SyncImpl. +type syncInstrument struct { + instrument SyncImpl +} + +// syncBoundInstrument contains a BoundSyncImpl. +type syncBoundInstrument struct { + boundInstrument BoundSyncImpl +} + +// asyncInstrument contains a AsyncImpl. +type asyncInstrument struct { + instrument AsyncImpl +} + +// SyncImpl returns the instrument that created this measurement. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (m Measurement) SyncImpl() SyncImpl { + return m.instrument +} + +// Number returns a number recorded in this measurement. +func (m Measurement) Number() number.Number { + return m.number +} + +// AsyncImpl returns the instrument that created this observation. +// This returns an implementation-level object for use by the SDK, +// users should not refer to this. +func (m Observation) AsyncImpl() AsyncImpl { + return m.instrument +} + +// Number returns a number recorded in this observation. +func (m Observation) Number() number.Number { + return m.number +} + +// AsyncImpl implements AsyncImpl. +func (a asyncInstrument) AsyncImpl() AsyncImpl { + return a.instrument +} + +// SyncImpl returns the implementation object for synchronous instruments. +func (s syncInstrument) SyncImpl() SyncImpl { + return s.instrument +} + +func (s syncInstrument) bind(labels []attribute.KeyValue) syncBoundInstrument { + return newSyncBoundInstrument(s.instrument.Bind(labels)) +} + +func (s syncInstrument) float64Measurement(value float64) Measurement { + return newMeasurement(s.instrument, number.NewFloat64Number(value)) +} + +func (s syncInstrument) int64Measurement(value int64) Measurement { + return newMeasurement(s.instrument, number.NewInt64Number(value)) +} + +func (s syncInstrument) directRecord(ctx context.Context, number number.Number, labels []attribute.KeyValue) { + s.instrument.RecordOne(ctx, number, labels) +} + +func (h syncBoundInstrument) directRecord(ctx context.Context, number number.Number) { + h.boundInstrument.RecordOne(ctx, number) +} + +// Unbind calls SyncImpl.Unbind. +func (h syncBoundInstrument) Unbind() { + h.boundInstrument.Unbind() +} + +// checkNewAsync receives an AsyncImpl and potential +// error, and returns the same types, checking for and ensuring that +// the returned interface is not nil. +func checkNewAsync(instrument AsyncImpl, err error) (asyncInstrument, error) { + if instrument == nil { + if err == nil { + err = ErrSDKReturnedNilImpl + } + instrument = NoopAsync{} + } + return asyncInstrument{ + instrument: instrument, + }, err +} + +// checkNewSync receives an SyncImpl and potential +// error, and returns the same types, checking for and ensuring that +// the returned interface is not nil. +func checkNewSync(instrument SyncImpl, err error) (syncInstrument, error) { + if instrument == nil { + if err == nil { + err = ErrSDKReturnedNilImpl + } + // Note: an alternate behavior would be to synthesize a new name + // or group all duplicately-named instruments of a certain type + // together and use a tag for the original name, e.g., + // name = 'invalid.counter.int64' + // label = 'original-name=duplicate-counter-name' + instrument = NoopSync{} + } + return syncInstrument{ + instrument: instrument, + }, err +} + +func newSyncBoundInstrument(boundInstrument BoundSyncImpl) syncBoundInstrument { + return syncBoundInstrument{ + boundInstrument: boundInstrument, + } +} + +func newMeasurement(instrument SyncImpl, number number.Number) Measurement { + return Measurement{ + instrument: instrument, + number: number, + } +} + +// wrapInt64CounterInstrument converts a SyncImpl into Int64Counter. +func wrapInt64CounterInstrument(syncInst SyncImpl, err error) (Int64Counter, error) { + common, err := checkNewSync(syncInst, err) + return Int64Counter{syncInstrument: common}, err +} + +// wrapFloat64CounterInstrument converts a SyncImpl into Float64Counter. +func wrapFloat64CounterInstrument(syncInst SyncImpl, err error) (Float64Counter, error) { + common, err := checkNewSync(syncInst, err) + return Float64Counter{syncInstrument: common}, err +} + +// wrapInt64UpDownCounterInstrument converts a SyncImpl into Int64UpDownCounter. +func wrapInt64UpDownCounterInstrument(syncInst SyncImpl, err error) (Int64UpDownCounter, error) { + common, err := checkNewSync(syncInst, err) + return Int64UpDownCounter{syncInstrument: common}, err +} + +// wrapFloat64UpDownCounterInstrument converts a SyncImpl into Float64UpDownCounter. +func wrapFloat64UpDownCounterInstrument(syncInst SyncImpl, err error) (Float64UpDownCounter, error) { + common, err := checkNewSync(syncInst, err) + return Float64UpDownCounter{syncInstrument: common}, err +} + +// wrapInt64ValueRecorderInstrument converts a SyncImpl into Int64ValueRecorder. +func wrapInt64ValueRecorderInstrument(syncInst SyncImpl, err error) (Int64ValueRecorder, error) { + common, err := checkNewSync(syncInst, err) + return Int64ValueRecorder{syncInstrument: common}, err +} + +// wrapFloat64ValueRecorderInstrument converts a SyncImpl into Float64ValueRecorder. +func wrapFloat64ValueRecorderInstrument(syncInst SyncImpl, err error) (Float64ValueRecorder, error) { + common, err := checkNewSync(syncInst, err) + return Float64ValueRecorder{syncInstrument: common}, err +} + +// Float64Counter is a metric that accumulates float64 values. +type Float64Counter struct { + syncInstrument +} + +// Int64Counter is a metric that accumulates int64 values. +type Int64Counter struct { + syncInstrument +} + +// BoundFloat64Counter is a bound instrument for Float64Counter. +// +// It inherits the Unbind function from syncBoundInstrument. +type BoundFloat64Counter struct { + syncBoundInstrument +} + +// BoundInt64Counter is a boundInstrument for Int64Counter. +// +// It inherits the Unbind function from syncBoundInstrument. +type BoundInt64Counter struct { + syncBoundInstrument +} + +// Bind creates a bound instrument for this counter. The labels are +// associated with values recorded via subsequent calls to Record. +func (c Float64Counter) Bind(labels ...attribute.KeyValue) (h BoundFloat64Counter) { + h.syncBoundInstrument = c.bind(labels) + return +} + +// Bind creates a bound instrument for this counter. The labels are +// associated with values recorded via subsequent calls to Record. +func (c Int64Counter) Bind(labels ...attribute.KeyValue) (h BoundInt64Counter) { + h.syncBoundInstrument = c.bind(labels) + return +} + +// Measurement creates a Measurement object to use with batch +// recording. +func (c Float64Counter) Measurement(value float64) Measurement { + return c.float64Measurement(value) +} + +// Measurement creates a Measurement object to use with batch +// recording. +func (c Int64Counter) Measurement(value int64) Measurement { + return c.int64Measurement(value) +} + +// Add adds the value to the counter's sum. The labels should contain +// the keys and values to be associated with this value. +func (c Float64Counter) Add(ctx context.Context, value float64, labels ...attribute.KeyValue) { + c.directRecord(ctx, number.NewFloat64Number(value), labels) +} + +// Add adds the value to the counter's sum. The labels should contain +// the keys and values to be associated with this value. +func (c Int64Counter) Add(ctx context.Context, value int64, labels ...attribute.KeyValue) { + c.directRecord(ctx, number.NewInt64Number(value), labels) +} + +// Add adds the value to the counter's sum using the labels +// previously bound to this counter via Bind() +func (b BoundFloat64Counter) Add(ctx context.Context, value float64) { + b.directRecord(ctx, number.NewFloat64Number(value)) +} + +// Add adds the value to the counter's sum using the labels +// previously bound to this counter via Bind() +func (b BoundInt64Counter) Add(ctx context.Context, value int64) { + b.directRecord(ctx, number.NewInt64Number(value)) +} + +// Float64UpDownCounter is a metric instrument that sums floating +// point values. +type Float64UpDownCounter struct { + syncInstrument +} + +// Int64UpDownCounter is a metric instrument that sums integer values. +type Int64UpDownCounter struct { + syncInstrument +} + +// BoundFloat64UpDownCounter is a bound instrument for Float64UpDownCounter. +// +// It inherits the Unbind function from syncBoundInstrument. +type BoundFloat64UpDownCounter struct { + syncBoundInstrument +} + +// BoundInt64UpDownCounter is a boundInstrument for Int64UpDownCounter. +// +// It inherits the Unbind function from syncBoundInstrument. +type BoundInt64UpDownCounter struct { + syncBoundInstrument +} + +// Bind creates a bound instrument for this counter. The labels are +// associated with values recorded via subsequent calls to Record. +func (c Float64UpDownCounter) Bind(labels ...attribute.KeyValue) (h BoundFloat64UpDownCounter) { + h.syncBoundInstrument = c.bind(labels) + return +} + +// Bind creates a bound instrument for this counter. The labels are +// associated with values recorded via subsequent calls to Record. +func (c Int64UpDownCounter) Bind(labels ...attribute.KeyValue) (h BoundInt64UpDownCounter) { + h.syncBoundInstrument = c.bind(labels) + return +} + +// Measurement creates a Measurement object to use with batch +// recording. +func (c Float64UpDownCounter) Measurement(value float64) Measurement { + return c.float64Measurement(value) +} + +// Measurement creates a Measurement object to use with batch +// recording. +func (c Int64UpDownCounter) Measurement(value int64) Measurement { + return c.int64Measurement(value) +} + +// Add adds the value to the counter's sum. The labels should contain +// the keys and values to be associated with this value. +func (c Float64UpDownCounter) Add(ctx context.Context, value float64, labels ...attribute.KeyValue) { + c.directRecord(ctx, number.NewFloat64Number(value), labels) +} + +// Add adds the value to the counter's sum. The labels should contain +// the keys and values to be associated with this value. +func (c Int64UpDownCounter) Add(ctx context.Context, value int64, labels ...attribute.KeyValue) { + c.directRecord(ctx, number.NewInt64Number(value), labels) +} + +// Add adds the value to the counter's sum using the labels +// previously bound to this counter via Bind() +func (b BoundFloat64UpDownCounter) Add(ctx context.Context, value float64) { + b.directRecord(ctx, number.NewFloat64Number(value)) +} + +// Add adds the value to the counter's sum using the labels +// previously bound to this counter via Bind() +func (b BoundInt64UpDownCounter) Add(ctx context.Context, value int64) { + b.directRecord(ctx, number.NewInt64Number(value)) +} + +// Float64ValueRecorder is a metric that records float64 values. +type Float64ValueRecorder struct { + syncInstrument +} + +// Int64ValueRecorder is a metric that records int64 values. +type Int64ValueRecorder struct { + syncInstrument +} + +// BoundFloat64ValueRecorder is a bound instrument for Float64ValueRecorder. +// +// It inherits the Unbind function from syncBoundInstrument. +type BoundFloat64ValueRecorder struct { + syncBoundInstrument +} + +// BoundInt64ValueRecorder is a bound instrument for Int64ValueRecorder. +// +// It inherits the Unbind function from syncBoundInstrument. +type BoundInt64ValueRecorder struct { + syncBoundInstrument +} + +// Bind creates a bound instrument for this ValueRecorder. The labels are +// associated with values recorded via subsequent calls to Record. +func (c Float64ValueRecorder) Bind(labels ...attribute.KeyValue) (h BoundFloat64ValueRecorder) { + h.syncBoundInstrument = c.bind(labels) + return +} + +// Bind creates a bound instrument for this ValueRecorder. The labels are +// associated with values recorded via subsequent calls to Record. +func (c Int64ValueRecorder) Bind(labels ...attribute.KeyValue) (h BoundInt64ValueRecorder) { + h.syncBoundInstrument = c.bind(labels) + return +} + +// Measurement creates a Measurement object to use with batch +// recording. +func (c Float64ValueRecorder) Measurement(value float64) Measurement { + return c.float64Measurement(value) +} + +// Measurement creates a Measurement object to use with batch +// recording. +func (c Int64ValueRecorder) Measurement(value int64) Measurement { + return c.int64Measurement(value) +} + +// Record adds a new value to the list of ValueRecorder's records. The +// labels should contain the keys and values to be associated with +// this value. +func (c Float64ValueRecorder) Record(ctx context.Context, value float64, labels ...attribute.KeyValue) { + c.directRecord(ctx, number.NewFloat64Number(value), labels) +} + +// Record adds a new value to the ValueRecorder's distribution. The +// labels should contain the keys and values to be associated with +// this value. +func (c Int64ValueRecorder) Record(ctx context.Context, value int64, labels ...attribute.KeyValue) { + c.directRecord(ctx, number.NewInt64Number(value), labels) +} + +// Record adds a new value to the ValueRecorder's distribution using the labels +// previously bound to the ValueRecorder via Bind(). +func (b BoundFloat64ValueRecorder) Record(ctx context.Context, value float64) { + b.directRecord(ctx, number.NewFloat64Number(value)) +} + +// Record adds a new value to the ValueRecorder's distribution using the labels +// previously bound to the ValueRecorder via Bind(). +func (b BoundInt64ValueRecorder) Record(ctx context.Context, value int64) { + b.directRecord(ctx, number.NewInt64Number(value)) +} diff --git a/vendor/go.opentelemetry.io/otel/api/metric/noop.go b/vendor/go.opentelemetry.io/otel/metric/metric_noop.go similarity index 69% rename from vendor/go.opentelemetry.io/otel/api/metric/noop.go rename to vendor/go.opentelemetry.io/otel/metric/metric_noop.go index de2c5681a9f9..30e57b6945bf 100644 --- a/vendor/go.opentelemetry.io/otel/api/metric/noop.go +++ b/vendor/go.opentelemetry.io/otel/metric/metric_noop.go @@ -12,27 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -package metric +package metric // import "go.opentelemetry.io/otel/metric" import ( "context" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/number" ) -type NoopProvider struct{} +type NoopMeterProvider struct{} type noopInstrument struct{} type noopBoundInstrument struct{} type NoopSync struct{ noopInstrument } type NoopAsync struct{ noopInstrument } -var _ Provider = NoopProvider{} +var _ MeterProvider = NoopMeterProvider{} var _ SyncImpl = NoopSync{} var _ BoundSyncImpl = noopBoundInstrument{} var _ AsyncImpl = NoopAsync{} -func (NoopProvider) Meter(_ string, _ ...MeterOption) Meter { +func (NoopMeterProvider) Meter(_ string, _ ...MeterOption) Meter { return Meter{} } @@ -44,15 +45,15 @@ func (noopInstrument) Descriptor() Descriptor { return Descriptor{} } -func (noopBoundInstrument) RecordOne(context.Context, Number) { +func (noopBoundInstrument) RecordOne(context.Context, number.Number) { } func (noopBoundInstrument) Unbind() { } -func (NoopSync) Bind([]label.KeyValue) BoundSyncImpl { +func (NoopSync) Bind([]attribute.KeyValue) BoundSyncImpl { return noopBoundInstrument{} } -func (NoopSync) RecordOne(context.Context, Number, []label.KeyValue) { +func (NoopSync) RecordOne(context.Context, number.Number, []attribute.KeyValue) { } diff --git a/vendor/go.opentelemetry.io/otel/api/metric/sdkapi.go b/vendor/go.opentelemetry.io/otel/metric/metric_sdkapi.go similarity index 81% rename from vendor/go.opentelemetry.io/otel/api/metric/sdkapi.go rename to vendor/go.opentelemetry.io/otel/metric/metric_sdkapi.go index 3c4e11ee4fb6..94164f7b4858 100644 --- a/vendor/go.opentelemetry.io/otel/api/metric/sdkapi.go +++ b/vendor/go.opentelemetry.io/otel/metric/metric_sdkapi.go @@ -12,19 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package metric +package metric // import "go.opentelemetry.io/otel/metric" import ( "context" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/number" ) // MeterImpl is the interface an SDK must implement to supply a Meter // implementation. type MeterImpl interface { // RecordBatch atomically records a batch of measurements. - RecordBatch(context.Context, []label.KeyValue, ...Measurement) + RecordBatch(ctx context.Context, labels []attribute.KeyValue, measurement ...Measurement) // NewSyncInstrument returns a newly constructed // synchronous instrument implementation or an error, should @@ -59,10 +60,10 @@ type SyncImpl interface { // Bind creates an implementation-level bound instrument, // binding a label set with this instrument implementation. - Bind(labels []label.KeyValue) BoundSyncImpl + Bind(labels []attribute.KeyValue) BoundSyncImpl // RecordOne captures a single synchronous metric event. - RecordOne(ctx context.Context, number Number, labels []label.KeyValue) + RecordOne(ctx context.Context, number number.Number, labels []attribute.KeyValue) } // BoundSyncImpl is the implementation-level interface to a @@ -70,7 +71,7 @@ type SyncImpl interface { type BoundSyncImpl interface { // RecordOne captures a single synchronous metric event. - RecordOne(ctx context.Context, number Number) + RecordOne(ctx context.Context, number number.Number) // Unbind frees the resources associated with this bound instrument. It // does not affect the metric this bound instrument was created through. @@ -85,10 +86,10 @@ type AsyncImpl interface { // WrapMeterImpl constructs a `Meter` implementation from a // `MeterImpl` implementation. -func WrapMeterImpl(impl MeterImpl, instrumentatioName string, opts ...MeterOption) Meter { +func WrapMeterImpl(impl MeterImpl, instrumentationName string, opts ...MeterOption) Meter { return Meter{ impl: impl, - name: instrumentatioName, - version: ConfigureMeter(opts).InstrumentationVersion, + name: instrumentationName, + version: NewMeterConfig(opts...).InstrumentationVersion, } } diff --git a/vendor/go.opentelemetry.io/otel/api/propagation/doc.go b/vendor/go.opentelemetry.io/otel/metric/number/doc.go similarity index 60% rename from vendor/go.opentelemetry.io/otel/api/propagation/doc.go rename to vendor/go.opentelemetry.io/otel/metric/number/doc.go index d2839f5be4b7..0649ff875e70 100644 --- a/vendor/go.opentelemetry.io/otel/api/propagation/doc.go +++ b/vendor/go.opentelemetry.io/otel/metric/number/doc.go @@ -12,5 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package propagation contains interface definition for HTTP propagators. -package propagation // import "go.opentelemetry.io/otel/api/propagation" +/* +Package number provides a number abstraction for instruments that +either support int64 or float64 input values. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. +*/ +package number // import "go.opentelemetry.io/otel/metric/number" diff --git a/vendor/go.opentelemetry.io/otel/api/metric/kind_string.go b/vendor/go.opentelemetry.io/otel/metric/number/kind_string.go similarity index 56% rename from vendor/go.opentelemetry.io/otel/api/metric/kind_string.go rename to vendor/go.opentelemetry.io/otel/metric/number/kind_string.go index eb1a0d503da6..6288c7ea295f 100644 --- a/vendor/go.opentelemetry.io/otel/api/metric/kind_string.go +++ b/vendor/go.opentelemetry.io/otel/metric/number/kind_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type=Kind"; DO NOT EDIT. -package metric +package number import "strconv" @@ -8,17 +8,13 @@ func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} - _ = x[ValueRecorderKind-0] - _ = x[ValueObserverKind-1] - _ = x[CounterKind-2] - _ = x[UpDownCounterKind-3] - _ = x[SumObserverKind-4] - _ = x[UpDownSumObserverKind-5] + _ = x[Int64Kind-0] + _ = x[Float64Kind-1] } -const _Kind_name = "ValueRecorderKindValueObserverKindCounterKindUpDownCounterKindSumObserverKindUpDownSumObserverKind" +const _Kind_name = "Int64KindFloat64Kind" -var _Kind_index = [...]uint8{0, 17, 34, 45, 62, 77, 98} +var _Kind_index = [...]uint8{0, 9, 20} func (i Kind) String() string { if i < 0 || i >= Kind(len(_Kind_index)-1) { diff --git a/vendor/go.opentelemetry.io/otel/api/metric/number.go b/vendor/go.opentelemetry.io/otel/metric/number/number.go similarity index 86% rename from vendor/go.opentelemetry.io/otel/api/metric/number.go rename to vendor/go.opentelemetry.io/otel/metric/number/number.go index c3ca0ed79238..3ec95e2014d7 100644 --- a/vendor/go.opentelemetry.io/otel/api/metric/number.go +++ b/vendor/go.opentelemetry.io/otel/metric/number/number.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -package metric +package number // import "go.opentelemetry.io/otel/metric/number" -//go:generate stringer -type=NumberKind +//go:generate stringer -type=Kind import ( "fmt" @@ -24,22 +24,22 @@ import ( "go.opentelemetry.io/otel/internal" ) -// NumberKind describes the data type of the Number. -type NumberKind int8 +// Kind describes the data type of the Number. +type Kind int8 const ( - // Int64NumberKind means that the Number stores int64. - Int64NumberKind NumberKind = iota - // Float64NumberKind means that the Number stores float64. - Float64NumberKind + // Int64Kind means that the Number stores int64. + Int64Kind Kind = iota + // Float64Kind means that the Number stores float64. + Float64Kind ) -// Zero returns a zero value for a given NumberKind -func (k NumberKind) Zero() Number { +// Zero returns a zero value for a given Kind +func (k Kind) Zero() Number { switch k { - case Int64NumberKind: + case Int64Kind: return NewInt64Number(0) - case Float64NumberKind: + case Float64Kind: return NewFloat64Number(0.) default: return Number(0) @@ -47,12 +47,12 @@ func (k NumberKind) Zero() Number { } // Minimum returns the minimum representable value -// for a given NumberKind -func (k NumberKind) Minimum() Number { +// for a given Kind +func (k Kind) Minimum() Number { switch k { - case Int64NumberKind: + case Int64Kind: return NewInt64Number(math.MinInt64) - case Float64NumberKind: + case Float64Kind: return NewFloat64Number(-1. * math.MaxFloat64) default: return Number(0) @@ -60,12 +60,12 @@ func (k NumberKind) Minimum() Number { } // Maximum returns the maximum representable value -// for a given NumberKind -func (k NumberKind) Maximum() Number { +// for a given Kind +func (k Kind) Maximum() Number { switch k { - case Int64NumberKind: + case Int64Kind: return NewInt64Number(math.MaxInt64) - case Float64NumberKind: + case Float64Kind: return NewFloat64Number(math.MaxFloat64) default: return Number(0) @@ -73,7 +73,7 @@ func (k NumberKind) Maximum() Number { } // Number represents either an integral or a floating point value. It -// needs to be accompanied with a source of NumberKind that describes +// needs to be accompanied with a source of Kind that describes // the actual type of the value stored within Number. type Number uint64 @@ -96,13 +96,11 @@ func NewFloat64Number(f float64) Number { // NewNumberSignChange returns a number with the same magnitude and // the opposite sign. `kind` must describe the kind of number in `nn`. -// -// Does not change Uint64NumberKind values. -func NewNumberSignChange(kind NumberKind, nn Number) Number { +func NewNumberSignChange(kind Kind, nn Number) Number { switch kind { - case Int64NumberKind: + case Int64Kind: return NewInt64Number(-nn.AsInt64()) - case Float64NumberKind: + case Float64Kind: return NewFloat64Number(-nn.AsFloat64()) } return nn @@ -182,11 +180,11 @@ func (n *Number) AsFloat64Ptr() *float64 { // CoerceToInt64 casts the number to int64. May result in // data/precision loss. -func (n *Number) CoerceToInt64(kind NumberKind) int64 { +func (n *Number) CoerceToInt64(kind Kind) int64 { switch kind { - case Int64NumberKind: + case Int64Kind: return n.AsInt64() - case Float64NumberKind: + case Float64Kind: return int64(n.AsFloat64()) default: // you get what you deserve @@ -196,11 +194,11 @@ func (n *Number) CoerceToInt64(kind NumberKind) int64 { // CoerceToFloat64 casts the number to float64. May result in // data/precision loss. -func (n *Number) CoerceToFloat64(kind NumberKind) float64 { +func (n *Number) CoerceToFloat64(kind Kind) float64 { switch kind { - case Int64NumberKind: + case Int64Kind: return float64(n.AsInt64()) - case Float64NumberKind: + case Float64Kind: return n.AsFloat64() default: // you get what you deserve @@ -330,18 +328,18 @@ func (n *Number) SwapFloat64Atomic(f float64) float64 { // AddNumber assumes that this and the passed number are of the passed // kind and adds the passed number to this number. -func (n *Number) AddNumber(kind NumberKind, nn Number) { +func (n *Number) AddNumber(kind Kind, nn Number) { switch kind { - case Int64NumberKind: + case Int64Kind: n.AddInt64(nn.AsInt64()) - case Float64NumberKind: + case Float64Kind: n.AddFloat64(nn.AsFloat64()) } } // AddRaw assumes that this number and the passed raw value are of the // passed kind and adds the passed raw value to this number. -func (n *Number) AddRaw(kind NumberKind, r uint64) { +func (n *Number) AddRaw(kind Kind, r uint64) { n.AddNumber(kind, NewNumberFromRaw(r)) } @@ -361,11 +359,11 @@ func (n *Number) AddFloat64(f float64) { // AddNumberAtomic assumes that this and the passed number are of the // passed kind and adds the passed number to this number atomically. -func (n *Number) AddNumberAtomic(kind NumberKind, nn Number) { +func (n *Number) AddNumberAtomic(kind Kind, nn Number) { switch kind { - case Int64NumberKind: + case Int64Kind: n.AddInt64Atomic(nn.AsInt64()) - case Float64NumberKind: + case Float64Kind: n.AddFloat64Atomic(nn.AsFloat64()) } } @@ -373,7 +371,7 @@ func (n *Number) AddNumberAtomic(kind NumberKind, nn Number) { // AddRawAtomic assumes that this number and the passed raw value are // of the passed kind and adds the passed raw value to this number // atomically. -func (n *Number) AddRawAtomic(kind NumberKind, r uint64) { +func (n *Number) AddRawAtomic(kind Kind, r uint64) { n.AddNumberAtomic(kind, NewNumberFromRaw(r)) } @@ -429,11 +427,11 @@ func (n *Number) CompareAndSwapFloat64(of, nf float64) bool { // 0 if the numbers are equal // -1 if the subject `n` is less than the argument `nn` // +1 if the subject `n` is greater than the argument `nn` -func (n *Number) CompareNumber(kind NumberKind, nn Number) int { +func (n *Number) CompareNumber(kind Kind, nn Number) int { switch kind { - case Int64NumberKind: + case Int64Kind: return n.CompareInt64(nn.AsInt64()) - case Float64NumberKind: + case Float64Kind: return n.CompareFloat64(nn.AsFloat64()) default: // you get what you deserve @@ -443,7 +441,7 @@ func (n *Number) CompareNumber(kind NumberKind, nn Number) int { // CompareRaw compares two numbers, where one is input as a raw // uint64, interpreting both values as a `kind` of number. -func (n *Number) CompareRaw(kind NumberKind, r uint64) int { +func (n *Number) CompareRaw(kind Kind, r uint64) int { return n.CompareNumber(kind, NewNumberFromRaw(r)) } @@ -482,17 +480,17 @@ func (n *Number) CompareFloat64(f float64) int { // - relations to zero // IsPositive returns true if the actual value is greater than zero. -func (n *Number) IsPositive(kind NumberKind) bool { +func (n *Number) IsPositive(kind Kind) bool { return n.compareWithZero(kind) > 0 } // IsNegative returns true if the actual value is less than zero. -func (n *Number) IsNegative(kind NumberKind) bool { +func (n *Number) IsNegative(kind Kind) bool { return n.compareWithZero(kind) < 0 } // IsZero returns true if the actual value is equal to zero. -func (n *Number) IsZero(kind NumberKind) bool { +func (n *Number) IsZero(kind Kind) bool { return n.compareWithZero(kind) == 0 } @@ -501,11 +499,11 @@ func (n *Number) IsZero(kind NumberKind) bool { // Emit returns a string representation of the raw value of the // Number. A %d is used for integral values, %f for floating point // values. -func (n *Number) Emit(kind NumberKind) string { +func (n *Number) Emit(kind Kind) string { switch kind { - case Int64NumberKind: + case Int64Kind: return fmt.Sprintf("%d", n.AsInt64()) - case Float64NumberKind: + case Float64Kind: return fmt.Sprintf("%f", n.AsFloat64()) default: return "" @@ -513,12 +511,12 @@ func (n *Number) Emit(kind NumberKind) string { } // AsInterface returns the number as an interface{}, typically used -// for NumberKind-correct JSON conversion. -func (n *Number) AsInterface(kind NumberKind) interface{} { +// for Kind-correct JSON conversion. +func (n *Number) AsInterface(kind Kind) interface{} { switch kind { - case Int64NumberKind: + case Int64Kind: return n.AsInt64() - case Float64NumberKind: + case Float64Kind: return n.AsFloat64() default: return math.NaN() @@ -527,11 +525,11 @@ func (n *Number) AsInterface(kind NumberKind) interface{} { // - private stuff -func (n *Number) compareWithZero(kind NumberKind) int { +func (n *Number) compareWithZero(kind Kind) int { switch kind { - case Int64NumberKind: + case Int64Kind: return n.CompareInt64(0) - case Float64NumberKind: + case Float64Kind: return n.CompareFloat64(0.) default: // you get what you deserve diff --git a/vendor/go.opentelemetry.io/otel/metric/registry/doc.go b/vendor/go.opentelemetry.io/otel/metric/registry/doc.go new file mode 100644 index 000000000000..a53ba4554557 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/metric/registry/doc.go @@ -0,0 +1,24 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* +Package registry provides a non-standalone implementation of +MeterProvider that adds uniqueness checking for instrument descriptors +on top of other MeterProvider it wraps. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. +*/ +package registry // import "go.opentelemetry.io/otel/metric/registry" diff --git a/vendor/go.opentelemetry.io/otel/api/metric/registry/registry.go b/vendor/go.opentelemetry.io/otel/metric/registry/registry.go similarity index 83% rename from vendor/go.opentelemetry.io/otel/api/metric/registry/registry.go rename to vendor/go.opentelemetry.io/otel/metric/registry/registry.go index 16b6883a9a60..0a42a0fdf8dc 100644 --- a/vendor/go.opentelemetry.io/otel/api/metric/registry/registry.go +++ b/vendor/go.opentelemetry.io/otel/metric/registry/registry.go @@ -12,23 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -package registry // import "go.opentelemetry.io/otel/api/metric/registry" +package registry // import "go.opentelemetry.io/otel/metric/registry" import ( "context" "fmt" "sync" - "go.opentelemetry.io/otel/api/metric" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" ) -// Provider is a standard metric.Provider for wrapping `MeterImpl` -type Provider struct { +// MeterProvider is a standard MeterProvider for wrapping `MeterImpl` +type MeterProvider struct { impl metric.MeterImpl } -var _ metric.Provider = (*Provider)(nil) +var _ metric.MeterProvider = (*MeterProvider)(nil) // uniqueInstrumentMeterImpl implements the metric.MeterImpl interface, adding // uniqueness checking for instrument descriptors. Use NewUniqueInstrumentMeter @@ -47,23 +47,23 @@ type key struct { InstrumentationVersion string } -// NewProvider returns a new provider that implements instrument +// NewMeterProvider returns a new provider that implements instrument // name-uniqueness checking. -func NewProvider(impl metric.MeterImpl) *Provider { - return &Provider{ +func NewMeterProvider(impl metric.MeterImpl) *MeterProvider { + return &MeterProvider{ impl: NewUniqueInstrumentMeterImpl(impl), } } -// Meter implements metric.Provider. -func (p *Provider) Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { +// Meter implements MeterProvider. +func (p *MeterProvider) Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { return metric.WrapMeterImpl(p.impl, instrumentationName, opts...) } // ErrMetricKindMismatch is the standard error for mismatched metric // instrument definitions. var ErrMetricKindMismatch = fmt.Errorf( - "A metric was already registered by this name with another kind or number type") + "a metric was already registered by this name with another kind or number type") // NewUniqueInstrumentMeterImpl returns a wrapped metric.MeterImpl with // the addition of uniqueness checking. @@ -75,7 +75,7 @@ func NewUniqueInstrumentMeterImpl(impl metric.MeterImpl) metric.MeterImpl { } // RecordBatch implements metric.MeterImpl. -func (u *uniqueInstrumentMeterImpl) RecordBatch(ctx context.Context, labels []label.KeyValue, ms ...metric.Measurement) { +func (u *uniqueInstrumentMeterImpl) RecordBatch(ctx context.Context, labels []attribute.KeyValue, ms ...metric.Measurement) { u.impl.RecordBatch(ctx, labels, ms...) } @@ -90,19 +90,19 @@ func keyOf(descriptor metric.Descriptor) key { // NewMetricKindMismatchError formats an error that describes a // mismatched metric instrument definition. func NewMetricKindMismatchError(desc metric.Descriptor) error { - return fmt.Errorf("Metric was %s (%s %s)registered as a %s %s: %w", + return fmt.Errorf("metric was %s (%s %s)registered as a %s %s: %w", desc.Name(), desc.InstrumentationName(), desc.InstrumentationVersion(), desc.NumberKind(), - desc.MetricKind(), + desc.InstrumentKind(), ErrMetricKindMismatch) } // Compatible determines whether two metric.Descriptors are considered // the same for the purpose of uniqueness checking. func Compatible(candidate, existing metric.Descriptor) bool { - return candidate.MetricKind() == existing.MetricKind() && + return candidate.InstrumentKind() == existing.InstrumentKind() && candidate.NumberKind() == existing.NumberKind() } diff --git a/vendor/go.opentelemetry.io/otel/pre_release.sh b/vendor/go.opentelemetry.io/otel/pre_release.sh index e09924b770e0..0de22169cfcb 100644 --- a/vendor/go.opentelemetry.io/otel/pre_release.sh +++ b/vendor/go.opentelemetry.io/otel/pre_release.sh @@ -54,7 +54,7 @@ if [[ ${TAG_FOUND} = ${TAG} ]] ; then exit -1 fi -# Get version for sdk/opentelemetry.go +# Get version for version.go OTEL_VERSION=$(echo "${TAG}" | grep -o '^v[0-9]\+\.[0-9]\+\.[0-9]\+') # Strip leading v OTEL_VERSION="${OTEL_VERSION#v}" @@ -68,13 +68,13 @@ if ! git diff --quiet; then \ exit 1 fi -# Update sdk/opentelemetry.go -cp ./sdk/opentelemetry.go ./sdk/opentelemetry.go.bak -sed "s/\(return \"\)[0-9]*\.[0-9]*\.[0-9]*\"/\1${OTEL_VERSION}\"/" ./sdk/opentelemetry.go.bak >./sdk/opentelemetry.go -rm -f ./sdk/opentelemetry.go.bak +# Update version.go +cp ./version.go ./version.go.bak +sed "s/\(return \"\)[0-9]*\.[0-9]*\.[0-9]*\"/\1${OTEL_VERSION}\"/" ./version.go.bak >./version.go +rm -f ./version.go.bak # Update go.mod -git checkout -b pre_release_${TAG} master +git checkout -b pre_release_${TAG} main PACKAGE_DIRS=$(find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; | egrep -v 'tools' | sed 's/^\.\///' | sort) for dir in $PACKAGE_DIRS; do @@ -91,5 +91,5 @@ git add . make ci git commit -m "Prepare for releasing $TAG" -printf "Now run following to verify the changes.\ngit diff master\n" +printf "Now run following to verify the changes.\ngit diff main\n" printf "\nThen push the changes to upstream\n" diff --git a/vendor/go.opentelemetry.io/otel/propagation.go b/vendor/go.opentelemetry.io/otel/propagation.go new file mode 100644 index 000000000000..d29aaa32c0b5 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/propagation.go @@ -0,0 +1,31 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otel // import "go.opentelemetry.io/otel" + +import ( + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/propagation" +) + +// GetTextMapPropagator returns the global TextMapPropagator. If none has been +// set, a No-Op TextMapPropagator is returned. +func GetTextMapPropagator() propagation.TextMapPropagator { + return global.TextMapPropagator() +} + +// SetTextMapPropagator sets propagator as the global TextMapPropagator. +func SetTextMapPropagator(propagator propagation.TextMapPropagator) { + global.SetTextMapPropagator(propagator) +} diff --git a/vendor/go.opentelemetry.io/otel/api/correlation/correlation_context_propagator.go b/vendor/go.opentelemetry.io/otel/propagation/baggage.go similarity index 53% rename from vendor/go.opentelemetry.io/otel/api/correlation/correlation_context_propagator.go rename to vendor/go.opentelemetry.io/otel/propagation/baggage.go index bf93e701fe13..bc76191892e3 100644 --- a/vendor/go.opentelemetry.io/otel/api/correlation/correlation_context_propagator.go +++ b/vendor/go.opentelemetry.io/otel/propagation/baggage.go @@ -12,40 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -package correlation +package propagation // import "go.opentelemetry.io/otel/propagation" import ( "context" "net/url" "strings" - "go.opentelemetry.io/otel/api/propagation" - "go.opentelemetry.io/otel/label" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/internal/baggage" ) -// Temporary header name until W3C finalizes format. -// https://github.com/open-telemetry/opentelemetry-specification/blob/18b2752ebe6c7f0cdd8c7b2bcbdceb0ae3f5ad95/specification/correlationcontext/api.md#header-name -const correlationContextHeader = "otcorrelations" +const baggageHeader = "baggage" -// CorrelationContext propagates Key:Values in W3C CorrelationContext -// format. -// nolint:golint -type CorrelationContext struct{} - -var _ propagation.HTTPPropagator = CorrelationContext{} +// Baggage is a propagator that supports the W3C Baggage format. +// +// This propagates user-defined baggage associated with a trace. The complete +// specification is defined at https://w3c.github.io/baggage/. +type Baggage struct{} -// DefaultHTTPPropagator returns the default context correlation HTTP -// propagator. -func DefaultHTTPPropagator() propagation.HTTPPropagator { - return CorrelationContext{} -} +var _ TextMapPropagator = Baggage{} -// Inject implements HTTPInjector. -func (CorrelationContext) Inject(ctx context.Context, supplier propagation.HTTPSupplier) { - correlationCtx := MapFromContext(ctx) +// Inject sets baggage key-values from ctx into the carrier. +func (b Baggage) Inject(ctx context.Context, carrier TextMapCarrier) { + baggageMap := baggage.MapFromContext(ctx) firstIter := true var headerValueBuilder strings.Builder - correlationCtx.Foreach(func(kv label.KeyValue) bool { + baggageMap.Foreach(func(kv attribute.KeyValue) bool { if !firstIter { headerValueBuilder.WriteRune(',') } @@ -57,21 +50,21 @@ func (CorrelationContext) Inject(ctx context.Context, supplier propagation.HTTPS }) if headerValueBuilder.Len() > 0 { headerString := headerValueBuilder.String() - supplier.Set(correlationContextHeader, headerString) + carrier.Set(baggageHeader, headerString) } } -// Extract implements HTTPExtractor. -func (CorrelationContext) Extract(ctx context.Context, supplier propagation.HTTPSupplier) context.Context { - correlationContext := supplier.Get(correlationContextHeader) - if correlationContext == "" { - return ctx +// Extract returns a copy of parent with the baggage from the carrier added. +func (b Baggage) Extract(parent context.Context, carrier TextMapCarrier) context.Context { + bVal := carrier.Get(baggageHeader) + if bVal == "" { + return parent } - contextValues := strings.Split(correlationContext, ",") - keyValues := make([]label.KeyValue, 0, len(contextValues)) - for _, contextValue := range contextValues { - valueAndProps := strings.Split(contextValue, ";") + baggageValues := strings.Split(bVal, ",") + keyValues := make([]attribute.KeyValue, 0, len(baggageValues)) + for _, baggageValue := range baggageValues { + valueAndProps := strings.Split(baggageValue, ";") if len(valueAndProps) < 1 { continue } @@ -99,20 +92,20 @@ func (CorrelationContext) Extract(ctx context.Context, supplier propagation.HTTP trimmedValueWithProps.WriteString(prop) } - keyValues = append(keyValues, label.String(trimmedName, trimmedValueWithProps.String())) + keyValues = append(keyValues, attribute.String(trimmedName, trimmedValueWithProps.String())) } if len(keyValues) > 0 { // Only update the context if valid values were found - return ContextWithMap(ctx, NewMap(MapUpdate{ + return baggage.ContextWithMap(parent, baggage.NewMap(baggage.MapUpdate{ MultiKV: keyValues, })) } - return ctx + return parent } -// GetAllKeys implements HTTPPropagator. -func (CorrelationContext) GetAllKeys() []string { - return []string{correlationContextHeader} +// Fields returns the keys who's values are set with Inject. +func (b Baggage) Fields() []string { + return []string{baggageHeader} } diff --git a/vendor/go.opentelemetry.io/otel/propagation/doc.go b/vendor/go.opentelemetry.io/otel/propagation/doc.go new file mode 100644 index 000000000000..89573f1baa91 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/propagation/doc.go @@ -0,0 +1,28 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* +Package propagation contains OpenTelemetry context propagators. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. + +OpenTelemetry propagators are used to extract and inject context data from and +into messages exchanged by applications. The propagator supported by this +package is the W3C Trace Context encoding +(https://www.w3.org/TR/trace-context/), and W3C Baggage +(https://w3c.github.io/baggage/). +*/ +package propagation // import "go.opentelemetry.io/otel/propagation" diff --git a/vendor/go.opentelemetry.io/otel/propagation/propagation.go b/vendor/go.opentelemetry.io/otel/propagation/propagation.go new file mode 100644 index 000000000000..9cfeb347a378 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/propagation/propagation.go @@ -0,0 +1,105 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package propagation // import "go.opentelemetry.io/otel/propagation" + +import ( + "context" + "net/http" +) + +// TextMapCarrier is the storage medium used by a TextMapPropagator. +type TextMapCarrier interface { + // Get returns the value associated with the passed key. + Get(key string) string + // Set stores the key-value pair. + Set(key string, value string) + // Keys lists the keys stored in this carrier. + Keys() []string +} + +// HeaderCarrier adapts http.Header to satisfy the TextMapCarrier interface. +type HeaderCarrier http.Header + +// Get returns the value associated with the passed key. +func (hc HeaderCarrier) Get(key string) string { + return http.Header(hc).Get(key) +} + +// Set stores the key-value pair. +func (hc HeaderCarrier) Set(key string, value string) { + http.Header(hc).Set(key, value) +} + +// Keys lists the keys stored in this carrier. +func (hc HeaderCarrier) Keys() []string { + keys := make([]string, 0, len(hc)) + for k := range hc { + keys = append(keys, k) + } + return keys +} + +// TextMapPropagator propagates cross-cutting concerns as key-value text +// pairs within a carrier that travels in-band across process boundaries. +type TextMapPropagator interface { + // Inject set cross-cutting concerns from the Context into the carrier. + Inject(ctx context.Context, carrier TextMapCarrier) + // Extract reads cross-cutting concerns from the carrier into a Context. + Extract(ctx context.Context, carrier TextMapCarrier) context.Context + // Fields returns the keys who's values are set with Inject. + Fields() []string +} + +type compositeTextMapPropagator []TextMapPropagator + +func (p compositeTextMapPropagator) Inject(ctx context.Context, carrier TextMapCarrier) { + for _, i := range p { + i.Inject(ctx, carrier) + } +} + +func (p compositeTextMapPropagator) Extract(ctx context.Context, carrier TextMapCarrier) context.Context { + for _, i := range p { + ctx = i.Extract(ctx, carrier) + } + return ctx +} + +func (p compositeTextMapPropagator) Fields() []string { + unique := make(map[string]struct{}) + for _, i := range p { + for _, k := range i.Fields() { + unique[k] = struct{}{} + } + } + + fields := make([]string, 0, len(unique)) + for k := range unique { + fields = append(fields, k) + } + return fields +} + +// NewCompositeTextMapPropagator returns a unified TextMapPropagator from the +// group of passed TextMapPropagator. This allows different cross-cutting +// concerns to be propagates in a unified manner. +// +// The returned TextMapPropagator will inject and extract cross-cutting +// concerns in the order the TextMapPropagators were provided. Additionally, +// the Fields method will return a de-duplicated slice of the keys that are +// set with the Inject method. +func NewCompositeTextMapPropagator(p ...TextMapPropagator) TextMapPropagator { + return compositeTextMapPropagator(p) +} diff --git a/vendor/go.opentelemetry.io/otel/propagation/trace_context.go b/vendor/go.opentelemetry.io/otel/propagation/trace_context.go new file mode 100644 index 000000000000..82de416bea64 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/propagation/trace_context.go @@ -0,0 +1,178 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package propagation // import "go.opentelemetry.io/otel/propagation" + +import ( + "context" + "encoding/hex" + "fmt" + "regexp" + "strings" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +const ( + supportedVersion = 0 + maxVersion = 254 + traceparentHeader = "traceparent" + tracestateHeader = "tracestate" +) + +// TraceContext is a propagator that supports the W3C Trace Context format +// (https://www.w3.org/TR/trace-context/) +// +// This propagator will propagate the traceparent and tracestate headers to +// guarantee traces are not broken. It is up to the users of this propagator +// to choose if they want to participate in a trace by modifying the +// traceparent header and relevant parts of the tracestate header containing +// their proprietary information. +type TraceContext struct{} + +var _ TextMapPropagator = TraceContext{} +var traceCtxRegExp = regexp.MustCompile("^(?P[0-9a-f]{2})-(?P[a-f0-9]{32})-(?P[a-f0-9]{16})-(?P[a-f0-9]{2})(?:-.*)?$") + +// Inject set tracecontext from the Context into the carrier. +func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) { + sc := trace.SpanContextFromContext(ctx) + if !sc.IsValid() { + return + } + + carrier.Set(tracestateHeader, sc.TraceState().String()) + + // Clear all flags other than the trace-context supported sampling bit. + flags := sc.TraceFlags() & trace.FlagsSampled + + h := fmt.Sprintf("%.2x-%s-%s-%s", + supportedVersion, + sc.TraceID(), + sc.SpanID(), + flags) + carrier.Set(traceparentHeader, h) +} + +// Extract reads tracecontext from the carrier into a returned Context. +// +// The returned Context will be a copy of ctx and contain the extracted +// tracecontext as the remote SpanContext. If the extracted tracecontext is +// invalid, the passed ctx will be returned directly instead. +func (tc TraceContext) Extract(ctx context.Context, carrier TextMapCarrier) context.Context { + sc := tc.extract(carrier) + if !sc.IsValid() { + return ctx + } + return trace.ContextWithRemoteSpanContext(ctx, sc) +} + +func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext { + h := carrier.Get(traceparentHeader) + if h == "" { + return trace.SpanContext{} + } + + matches := traceCtxRegExp.FindStringSubmatch(h) + + if len(matches) == 0 { + return trace.SpanContext{} + } + + if len(matches) < 5 { // four subgroups plus the overall match + return trace.SpanContext{} + } + + if len(matches[1]) != 2 { + return trace.SpanContext{} + } + ver, err := hex.DecodeString(matches[1]) + if err != nil { + return trace.SpanContext{} + } + version := int(ver[0]) + if version > maxVersion { + return trace.SpanContext{} + } + + if version == 0 && len(matches) != 5 { // four subgroups plus the overall match + return trace.SpanContext{} + } + + if len(matches[2]) != 32 { + return trace.SpanContext{} + } + + var scc trace.SpanContextConfig + + scc.TraceID, err = trace.TraceIDFromHex(matches[2][:32]) + if err != nil { + return trace.SpanContext{} + } + + if len(matches[3]) != 16 { + return trace.SpanContext{} + } + scc.SpanID, err = trace.SpanIDFromHex(matches[3]) + if err != nil { + return trace.SpanContext{} + } + + if len(matches[4]) != 2 { + return trace.SpanContext{} + } + opts, err := hex.DecodeString(matches[4]) + if err != nil || len(opts) < 1 || (version == 0 && opts[0] > 2) { + return trace.SpanContext{} + } + // Clear all flags other than the trace-context supported sampling bit. + scc.TraceFlags = trace.TraceFlags(opts[0]) & trace.FlagsSampled + + scc.TraceState = parseTraceState(carrier.Get(tracestateHeader)) + scc.Remote = true + + sc := trace.NewSpanContext(scc) + if !sc.IsValid() { + return trace.SpanContext{} + } + + return sc +} + +// Fields returns the keys who's values are set with Inject. +func (tc TraceContext) Fields() []string { + return []string{traceparentHeader, tracestateHeader} +} + +func parseTraceState(in string) trace.TraceState { + if in == "" { + return trace.TraceState{} + } + + kvs := []attribute.KeyValue{} + for _, entry := range strings.Split(in, ",") { + parts := strings.SplitN(entry, "=", 2) + if len(parts) != 2 { + // Parse failure, abort! + return trace.TraceState{} + } + kvs = append(kvs, attribute.String(parts[0], parts[1])) + } + + // Ignoring error here as "failure to parse tracestate MUST NOT + // affect the parsing of traceparent." + // https://www.w3.org/TR/trace-context/#tracestate-header + ts, _ := trace.TraceStateFromKeyValues(kvs...) + return ts +} diff --git a/vendor/go.opentelemetry.io/otel/tag.sh b/vendor/go.opentelemetry.io/otel/tag.sh index 2a0ef1d26c23..70767c70377e 100644 --- a/vendor/go.opentelemetry.io/otel/tag.sh +++ b/vendor/go.opentelemetry.io/otel/tag.sh @@ -17,7 +17,7 @@ readonly PROGNAME=$(basename "$0") readonly PROGDIR=$(readlink -m "$(dirname "$0")") -readonly EXCLUDE_PACKAGES="tools" +readonly EXCLUDE_PACKAGES="internal/tools" readonly SEMVER_REGEX="v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?" usage() { diff --git a/vendor/go.opentelemetry.io/otel/api/global/trace.go b/vendor/go.opentelemetry.io/otel/trace.go similarity index 58% rename from vendor/go.opentelemetry.io/otel/api/global/trace.go rename to vendor/go.opentelemetry.io/otel/trace.go index 5c23325b7514..1d5ffb8ea574 100644 --- a/vendor/go.opentelemetry.io/otel/api/global/trace.go +++ b/vendor/go.opentelemetry.io/otel/trace.go @@ -12,33 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -package global +package otel // import "go.opentelemetry.io/otel" import ( - "go.opentelemetry.io/otel/api/global/internal" - "go.opentelemetry.io/otel/api/trace" + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/trace" ) // Tracer creates a named tracer that implements Tracer interface. // If the name is an empty string then provider uses default name. // -// This is short for TraceProvider().Tracer(name) +// This is short for GetTracerProvider().Tracer(name) func Tracer(name string) trace.Tracer { - return TraceProvider().Tracer(name) + return GetTracerProvider().Tracer(name) } -// TraceProvider returns the registered global trace provider. -// If none is registered then an instance of trace.NoopProvider is returned. +// GetTracerProvider returns the registered global trace provider. +// If none is registered then an instance of NoopTracerProvider is returned. // // Use the trace provider to create a named tracer. E.g. -// tracer := global.TraceProvider().Tracer("example.com/foo") +// tracer := global.GetTracerProvider().Tracer("example.com/foo") // or // tracer := global.Tracer("example.com/foo") -func TraceProvider() trace.Provider { - return internal.TraceProvider() +func GetTracerProvider() trace.TracerProvider { + return global.TracerProvider() } -// SetTraceProvider registers `tp` as the global trace provider. -func SetTraceProvider(tp trace.Provider) { - internal.SetTraceProvider(tp) +// SetTracerProvider registers `tp` as the global trace provider. +func SetTracerProvider(tp trace.TracerProvider) { + global.SetTracerProvider(tp) } diff --git a/vendor/go.opentelemetry.io/otel/trace/LICENSE b/vendor/go.opentelemetry.io/otel/trace/LICENSE new file mode 100644 index 000000000000..261eeb9e9f8b --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/trace/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/go.opentelemetry.io/otel/trace/config.go b/vendor/go.opentelemetry.io/otel/trace/config.go new file mode 100644 index 000000000000..ea30ee35f153 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/trace/config.go @@ -0,0 +1,205 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "time" + + "go.opentelemetry.io/otel/attribute" +) + +// TracerConfig is a group of options for a Tracer. +type TracerConfig struct { + // InstrumentationVersion is the version of the library providing + // instrumentation. + InstrumentationVersion string +} + +// NewTracerConfig applies all the options to a returned TracerConfig. +func NewTracerConfig(options ...TracerOption) *TracerConfig { + config := new(TracerConfig) + for _, option := range options { + option.ApplyTracer(config) + } + return config +} + +// TracerOption applies an option to a TracerConfig. +type TracerOption interface { + ApplyTracer(*TracerConfig) + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() +} + +// SpanConfig is a group of options for a Span. +type SpanConfig struct { + // Attributes describe the associated qualities of a Span. + Attributes []attribute.KeyValue + // Timestamp is a time in a Span life-cycle. + Timestamp time.Time + // Links are the associations a Span has with other Spans. + Links []Link + // NewRoot identifies a Span as the root Span for a new trace. This is + // commonly used when an existing trace crosses trust boundaries and the + // remote parent span context should be ignored for security. + NewRoot bool + // SpanKind is the role a Span has in a trace. + SpanKind SpanKind +} + +// NewSpanConfig applies all the options to a returned SpanConfig. +// No validation is performed on the returned SpanConfig (e.g. no uniqueness +// checking or bounding of data), it is left to the SDK to perform this +// action. +func NewSpanConfig(options ...SpanOption) *SpanConfig { + c := new(SpanConfig) + for _, option := range options { + option.ApplySpan(c) + } + return c +} + +// SpanOption applies an option to a SpanConfig. +type SpanOption interface { + ApplySpan(*SpanConfig) + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() +} + +// NewEventConfig applies all the EventOptions to a returned SpanConfig. If no +// timestamp option is passed, the returned SpanConfig will have a Timestamp +// set to the call time, otherwise no validation is performed on the returned +// SpanConfig. +func NewEventConfig(options ...EventOption) *SpanConfig { + c := new(SpanConfig) + for _, option := range options { + option.ApplyEvent(c) + } + if c.Timestamp.IsZero() { + c.Timestamp = time.Now() + } + return c +} + +// EventOption applies span event options to a SpanConfig. +type EventOption interface { + ApplyEvent(*SpanConfig) + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() +} + +// LifeCycleOption applies span life-cycle options to a SpanConfig. These +// options set values releated to events in a spans life-cycle like starting, +// ending, experiencing an error and other user defined notable events. +type LifeCycleOption interface { + SpanOption + EventOption +} + +type attributeSpanOption []attribute.KeyValue + +func (o attributeSpanOption) ApplySpan(c *SpanConfig) { o.apply(c) } +func (o attributeSpanOption) ApplyEvent(c *SpanConfig) { o.apply(c) } +func (attributeSpanOption) private() {} +func (o attributeSpanOption) apply(c *SpanConfig) { + c.Attributes = append(c.Attributes, []attribute.KeyValue(o)...) +} + +// WithAttributes adds the attributes related to a span life-cycle event. +// These attributes are used to describe the work a Span represents when this +// option is provided to a Span's start or end events. Otherwise, these +// attributes provide additional information about the event being recorded +// (e.g. error, state change, processing progress, system event). +// +// If multiple of these options are passed the attributes of each successive +// option will extend the attributes instead of overwriting. There is no +// guarantee of uniqueness in the resulting attributes. +func WithAttributes(attributes ...attribute.KeyValue) LifeCycleOption { + return attributeSpanOption(attributes) +} + +type timestampSpanOption time.Time + +func (o timestampSpanOption) ApplySpan(c *SpanConfig) { o.apply(c) } +func (o timestampSpanOption) ApplyEvent(c *SpanConfig) { o.apply(c) } +func (timestampSpanOption) private() {} +func (o timestampSpanOption) apply(c *SpanConfig) { c.Timestamp = time.Time(o) } + +// WithTimestamp sets the time of a Span life-cycle moment (e.g. started, +// stopped, errored). +func WithTimestamp(t time.Time) LifeCycleOption { + return timestampSpanOption(t) +} + +type linksSpanOption []Link + +func (o linksSpanOption) ApplySpan(c *SpanConfig) { c.Links = append(c.Links, []Link(o)...) } +func (linksSpanOption) private() {} + +// WithLinks adds links to a Span. The links are added to the existing Span +// links, i.e. this does not overwrite. +func WithLinks(links ...Link) SpanOption { + return linksSpanOption(links) +} + +type newRootSpanOption bool + +func (o newRootSpanOption) ApplySpan(c *SpanConfig) { c.NewRoot = bool(o) } +func (newRootSpanOption) private() {} + +// WithNewRoot specifies that the Span should be treated as a root Span. Any +// existing parent span context will be ignored when defining the Span's trace +// identifiers. +func WithNewRoot() SpanOption { + return newRootSpanOption(true) +} + +type spanKindSpanOption SpanKind + +func (o spanKindSpanOption) ApplySpan(c *SpanConfig) { c.SpanKind = SpanKind(o) } +func (o spanKindSpanOption) private() {} + +// WithSpanKind sets the SpanKind of a Span. +func WithSpanKind(kind SpanKind) SpanOption { + return spanKindSpanOption(kind) +} + +// InstrumentationOption is an interface for applying instrumentation specific +// options. +type InstrumentationOption interface { + TracerOption +} + +// WithInstrumentationVersion sets the instrumentation version. +func WithInstrumentationVersion(version string) InstrumentationOption { + return instrumentationVersionOption(version) +} + +type instrumentationVersionOption string + +func (i instrumentationVersionOption) ApplyTracer(config *TracerConfig) { + config.InstrumentationVersion = string(i) +} + +func (instrumentationVersionOption) private() {} diff --git a/vendor/go.opentelemetry.io/otel/trace/context.go b/vendor/go.opentelemetry.io/otel/trace/context.go new file mode 100644 index 000000000000..76f9a083c409 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/trace/context.go @@ -0,0 +1,61 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace // import "go.opentelemetry.io/otel/trace" + +import "context" + +type traceContextKeyType int + +const currentSpanKey traceContextKeyType = iota + +// ContextWithSpan returns a copy of parent with span set as the current Span. +func ContextWithSpan(parent context.Context, span Span) context.Context { + return context.WithValue(parent, currentSpanKey, span) +} + +// ContextWithSpanContext returns a copy of parent with sc as the current +// Span. The Span implementation that wraps sc is non-recording and performs +// no operations other than to return sc as the SpanContext from the +// SpanContext method. +func ContextWithSpanContext(parent context.Context, sc SpanContext) context.Context { + return ContextWithSpan(parent, nonRecordingSpan{sc: sc}) +} + +// ContextWithRemoteSpanContext returns a copy of parent with rsc set explicly +// as a remote SpanContext and as the current Span. The Span implementation +// that wraps rsc is non-recording and performs no operations other than to +// return rsc as the SpanContext from the SpanContext method. +func ContextWithRemoteSpanContext(parent context.Context, rsc SpanContext) context.Context { + return ContextWithSpanContext(parent, rsc.WithRemote(true)) +} + +// SpanFromContext returns the current Span from ctx. +// +// If no Span is currently set in ctx an implementation of a Span that +// performs no operations is returned. +func SpanFromContext(ctx context.Context) Span { + if ctx == nil { + return noopSpan{} + } + if span, ok := ctx.Value(currentSpanKey).(Span); ok { + return span + } + return noopSpan{} +} + +// SpanContextFromContext returns the current Span's SpanContext. +func SpanContextFromContext(ctx context.Context) SpanContext { + return SpanFromContext(ctx).SpanContext() +} diff --git a/vendor/go.opentelemetry.io/otel/trace/doc.go b/vendor/go.opentelemetry.io/otel/trace/doc.go new file mode 100644 index 000000000000..c962f3bc6229 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/trace/doc.go @@ -0,0 +1,70 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* +Package trace provides an implementation of the tracing part of the +OpenTelemetry API. + +This package is currently in a pre-GA phase. Backwards incompatible changes +may be introduced in subsequent minor version releases as we work to track the +evolving OpenTelemetry specification and user feedback. + +To participate in distributed traces a Span needs to be created for the +operation being performed as part of a traced workflow. It its simplest form: + + var tracer trace.Tracer + + func init() { + tracer = otel.Tracer("instrumentation/package/name") + } + + func operation(ctx context.Context) { + var span trace.Span + ctx, span = tracer.Start(ctx, "operation") + defer span.End() + // ... + } + +A Tracer is unique to the instrumentation and is used to create Spans. +Instrumentation should be designed to accept a TracerProvider from which it +can create its own unique Tracer. Alternatively, the registered global +TracerProvider from the go.opentelemetry.io/otel package can be used as +a default. + + const ( + name = "instrumentation/package/name" + version = "0.1.0" + ) + + type Instrumentation struct { + tracer trace.Tracer + } + + func NewInstrumentation(tp trace.TracerProvider) *Instrumentation { + if tp == nil { + tp = otel.TracerProvider() + } + return &Instrumentation{ + tracer: tp.Tracer(name, trace.WithInstrumentationVersion(version)), + } + } + + func operation(ctx context.Context, inst *Instrumentation) { + var span trace.Span + ctx, span = inst.tracer.Start(ctx, "operation") + defer span.End() + // ... + } +*/ +package trace // import "go.opentelemetry.io/otel/trace" diff --git a/vendor/go.opentelemetry.io/otel/trace/go.mod b/vendor/go.opentelemetry.io/otel/trace/go.mod new file mode 100644 index 000000000000..914e4f4384a3 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/trace/go.mod @@ -0,0 +1,53 @@ +module go.opentelemetry.io/otel/trace + +go 1.14 + +replace go.opentelemetry.io/otel => ../ + +replace go.opentelemetry.io/otel/bridge/opencensus => ../bridge/opencensus + +replace go.opentelemetry.io/otel/bridge/opentracing => ../bridge/opentracing + +replace go.opentelemetry.io/otel/example/jaeger => ../example/jaeger + +replace go.opentelemetry.io/otel/example/namedtracer => ../example/namedtracer + +replace go.opentelemetry.io/otel/example/opencensus => ../example/opencensus + +replace go.opentelemetry.io/otel/example/otel-collector => ../example/otel-collector + +replace go.opentelemetry.io/otel/example/prom-collector => ../example/prom-collector + +replace go.opentelemetry.io/otel/example/prometheus => ../example/prometheus + +replace go.opentelemetry.io/otel/example/zipkin => ../example/zipkin + +replace go.opentelemetry.io/otel/exporters/metric/prometheus => ../exporters/metric/prometheus + +replace go.opentelemetry.io/otel/exporters/otlp => ../exporters/otlp + +replace go.opentelemetry.io/otel/exporters/stdout => ../exporters/stdout + +replace go.opentelemetry.io/otel/exporters/trace/jaeger => ../exporters/trace/jaeger + +replace go.opentelemetry.io/otel/exporters/trace/zipkin => ../exporters/trace/zipkin + +replace go.opentelemetry.io/otel/internal/tools => ../internal/tools + +replace go.opentelemetry.io/otel/metric => ../metric + +replace go.opentelemetry.io/otel/oteltest => ../oteltest + +replace go.opentelemetry.io/otel/sdk => ../sdk + +replace go.opentelemetry.io/otel/sdk/export/metric => ../sdk/export/metric + +replace go.opentelemetry.io/otel/sdk/metric => ../sdk/metric + +replace go.opentelemetry.io/otel/trace => ./ + +require ( + github.com/google/go-cmp v0.5.5 + github.com/stretchr/testify v1.7.0 + go.opentelemetry.io/otel v0.20.0 +) diff --git a/vendor/go.opentelemetry.io/otel/trace/go.sum b/vendor/go.opentelemetry.io/otel/trace/go.sum new file mode 100644 index 000000000000..b69f2e56da0f --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/trace/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/go.opentelemetry.io/otel/otel.go b/vendor/go.opentelemetry.io/otel/trace/nonrecording.go similarity index 60% rename from vendor/go.opentelemetry.io/otel/otel.go rename to vendor/go.opentelemetry.io/otel/trace/nonrecording.go index 7d1c424bff16..88fcb81611f9 100644 --- a/vendor/go.opentelemetry.io/otel/otel.go +++ b/vendor/go.opentelemetry.io/otel/trace/nonrecording.go @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -package otel +package trace // import "go.opentelemetry.io/otel/trace" -import ( - "go.opentelemetry.io/otel/api/metric" - "go.opentelemetry.io/otel/api/propagation" - "go.opentelemetry.io/otel/api/trace" -) +// nonRecordingSpan is a minimal implementation of a Span that wraps a +// SpanContext. It performs no operations other than to return the wrapped +// SpanContext. +type nonRecordingSpan struct { + noopSpan -type Tracer = trace.Tracer + sc SpanContext +} -type Meter = metric.Meter - -type Propagators = propagation.Propagators +// SpanContext returns the wrapped SpanContext. +func (s nonRecordingSpan) SpanContext() SpanContext { return s.sc } diff --git a/vendor/go.opentelemetry.io/otel/trace/noop.go b/vendor/go.opentelemetry.io/otel/trace/noop.go new file mode 100644 index 000000000000..4a20f20cb41d --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/trace/noop.go @@ -0,0 +1,84 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace // import "go.opentelemetry.io/otel/trace" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" +) + +// NewNoopTracerProvider returns an implementation of TracerProvider that +// performs no operations. The Tracer and Spans created from the returned +// TracerProvider also perform no operations. +func NewNoopTracerProvider() TracerProvider { + return noopTracerProvider{} +} + +type noopTracerProvider struct{} + +var _ TracerProvider = noopTracerProvider{} + +// Tracer returns noop implementation of Tracer. +func (p noopTracerProvider) Tracer(string, ...TracerOption) Tracer { + return noopTracer{} +} + +// noopTracer is an implementation of Tracer that preforms no operations. +type noopTracer struct{} + +var _ Tracer = noopTracer{} + +// Start starts a noop span. +func (t noopTracer) Start(ctx context.Context, name string, _ ...SpanOption) (context.Context, Span) { + span := noopSpan{} + return ContextWithSpan(ctx, span), span +} + +// noopSpan is an implementation of Span that preforms no operations. +type noopSpan struct{} + +var _ Span = noopSpan{} + +// SpanContext returns an empty span context. +func (noopSpan) SpanContext() SpanContext { return SpanContext{} } + +// IsRecording always returns false. +func (noopSpan) IsRecording() bool { return false } + +// SetStatus does nothing. +func (noopSpan) SetStatus(codes.Code, string) {} + +// SetError does nothing. +func (noopSpan) SetError(bool) {} + +// SetAttributes does nothing. +func (noopSpan) SetAttributes(...attribute.KeyValue) {} + +// End does nothing. +func (noopSpan) End(...SpanOption) {} + +// RecordError does nothing. +func (noopSpan) RecordError(error, ...EventOption) {} + +// Tracer returns the Tracer that created this Span. +func (noopSpan) Tracer() Tracer { return noopTracer{} } + +// AddEvent does nothing. +func (noopSpan) AddEvent(string, ...EventOption) {} + +// SetName does nothing. +func (noopSpan) SetName(string) {} diff --git a/vendor/go.opentelemetry.io/otel/trace/trace.go b/vendor/go.opentelemetry.io/otel/trace/trace.go new file mode 100644 index 000000000000..d372e7d9d722 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/trace/trace.go @@ -0,0 +1,673 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace // import "go.opentelemetry.io/otel/trace" + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "regexp" + "strings" + "time" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" +) + +const ( + // FlagsSampled is a bitmask with the sampled bit set. A SpanContext + // with the sampling bit set means the span is sampled. + FlagsSampled = TraceFlags(0x01) + + errInvalidHexID errorConst = "trace-id and span-id can only contain [0-9a-f] characters, all lowercase" + + errInvalidTraceIDLength errorConst = "hex encoded trace-id must have length equals to 32" + errNilTraceID errorConst = "trace-id can't be all zero" + + errInvalidSpanIDLength errorConst = "hex encoded span-id must have length equals to 16" + errNilSpanID errorConst = "span-id can't be all zero" + + // based on the W3C Trace Context specification, see https://www.w3.org/TR/trace-context-1/#tracestate-header + traceStateKeyFormat = `[a-z][_0-9a-z\-\*\/]{0,255}` + traceStateKeyFormatWithMultiTenantVendor = `[a-z0-9][_0-9a-z\-\*\/]{0,240}@[a-z][_0-9a-z\-\*\/]{0,13}` + traceStateValueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]{0,255}[\x21-\x2b\x2d-\x3c\x3e-\x7e]` + + traceStateMaxListMembers = 32 + + errInvalidTraceStateKeyValue errorConst = "provided key or value is not valid according to the" + + " W3C Trace Context specification" + errInvalidTraceStateMembersNumber errorConst = "trace state would exceed the maximum limit of members (32)" + errInvalidTraceStateDuplicate errorConst = "trace state key/value pairs with duplicate keys provided" +) + +type errorConst string + +func (e errorConst) Error() string { + return string(e) +} + +// TraceID is a unique identity of a trace. +// nolint:golint +type TraceID [16]byte + +var nilTraceID TraceID +var _ json.Marshaler = nilTraceID + +// IsValid checks whether the trace TraceID is valid. A valid trace ID does +// not consist of zeros only. +func (t TraceID) IsValid() bool { + return !bytes.Equal(t[:], nilTraceID[:]) +} + +// MarshalJSON implements a custom marshal function to encode TraceID +// as a hex string. +func (t TraceID) MarshalJSON() ([]byte, error) { + return json.Marshal(t.String()) +} + +// String returns the hex string representation form of a TraceID +func (t TraceID) String() string { + return hex.EncodeToString(t[:]) +} + +// SpanID is a unique identity of a span in a trace. +type SpanID [8]byte + +var nilSpanID SpanID +var _ json.Marshaler = nilSpanID + +// IsValid checks whether the SpanID is valid. A valid SpanID does not consist +// of zeros only. +func (s SpanID) IsValid() bool { + return !bytes.Equal(s[:], nilSpanID[:]) +} + +// MarshalJSON implements a custom marshal function to encode SpanID +// as a hex string. +func (s SpanID) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// String returns the hex string representation form of a SpanID +func (s SpanID) String() string { + return hex.EncodeToString(s[:]) +} + +// TraceIDFromHex returns a TraceID from a hex string if it is compliant with +// the W3C trace-context specification. See more at +// https://www.w3.org/TR/trace-context/#trace-id +// nolint:golint +func TraceIDFromHex(h string) (TraceID, error) { + t := TraceID{} + if len(h) != 32 { + return t, errInvalidTraceIDLength + } + + if err := decodeHex(h, t[:]); err != nil { + return t, err + } + + if !t.IsValid() { + return t, errNilTraceID + } + return t, nil +} + +// SpanIDFromHex returns a SpanID from a hex string if it is compliant +// with the w3c trace-context specification. +// See more at https://www.w3.org/TR/trace-context/#parent-id +func SpanIDFromHex(h string) (SpanID, error) { + s := SpanID{} + if len(h) != 16 { + return s, errInvalidSpanIDLength + } + + if err := decodeHex(h, s[:]); err != nil { + return s, err + } + + if !s.IsValid() { + return s, errNilSpanID + } + return s, nil +} + +func decodeHex(h string, b []byte) error { + for _, r := range h { + switch { + case 'a' <= r && r <= 'f': + continue + case '0' <= r && r <= '9': + continue + default: + return errInvalidHexID + } + } + + decoded, err := hex.DecodeString(h) + if err != nil { + return err + } + + copy(b, decoded) + return nil +} + +// TraceState provides additional vendor-specific trace identification information +// across different distributed tracing systems. It represents an immutable list consisting +// of key/value pairs. There can be a maximum of 32 entries in the list. +// +// Key and value of each list member must be valid according to the W3C Trace Context specification +// (see https://www.w3.org/TR/trace-context-1/#key and https://www.w3.org/TR/trace-context-1/#value +// respectively). +// +// Trace state must be valid according to the W3C Trace Context specification at all times. All +// mutating operations validate their input and, in case of valid parameters, return a new TraceState. +type TraceState struct { //nolint:golint + // TODO @matej-g: Consider implementing this as attribute.Set, see + // comment https://github.com/open-telemetry/opentelemetry-go/pull/1340#discussion_r540599226 + kvs []attribute.KeyValue +} + +var _ json.Marshaler = TraceState{} +var _ json.Marshaler = SpanContext{} + +var keyFormatRegExp = regexp.MustCompile( + `^((` + traceStateKeyFormat + `)|(` + traceStateKeyFormatWithMultiTenantVendor + `))$`, +) +var valueFormatRegExp = regexp.MustCompile(`^(` + traceStateValueFormat + `)$`) + +// MarshalJSON implements a custom marshal function to encode trace state. +func (ts TraceState) MarshalJSON() ([]byte, error) { + return json.Marshal(ts.kvs) +} + +// String returns trace state as a string valid according to the +// W3C Trace Context specification. +func (ts TraceState) String() string { + var sb strings.Builder + + for i, kv := range ts.kvs { + sb.WriteString((string)(kv.Key)) + sb.WriteByte('=') + sb.WriteString(kv.Value.Emit()) + + if i != len(ts.kvs)-1 { + sb.WriteByte(',') + } + } + + return sb.String() +} + +// Get returns a value for given key from the trace state. +// If no key is found or provided key is invalid, returns an empty value. +func (ts TraceState) Get(key attribute.Key) attribute.Value { + if !isTraceStateKeyValid(key) { + return attribute.Value{} + } + + for _, kv := range ts.kvs { + if kv.Key == key { + return kv.Value + } + } + + return attribute.Value{} +} + +// Insert adds a new key/value, if one doesn't exists; otherwise updates the existing entry. +// The new or updated entry is always inserted at the beginning of the TraceState, i.e. +// on the left side, as per the W3C Trace Context specification requirement. +func (ts TraceState) Insert(entry attribute.KeyValue) (TraceState, error) { + if !isTraceStateKeyValueValid(entry) { + return ts, errInvalidTraceStateKeyValue + } + + ckvs := ts.copyKVsAndDeleteEntry(entry.Key) + if len(ckvs)+1 > traceStateMaxListMembers { + return ts, errInvalidTraceStateMembersNumber + } + + ckvs = append(ckvs, attribute.KeyValue{}) + copy(ckvs[1:], ckvs) + ckvs[0] = entry + + return TraceState{ckvs}, nil +} + +// Delete removes specified entry from the trace state. +func (ts TraceState) Delete(key attribute.Key) (TraceState, error) { + if !isTraceStateKeyValid(key) { + return ts, errInvalidTraceStateKeyValue + } + + return TraceState{ts.copyKVsAndDeleteEntry(key)}, nil +} + +// IsEmpty returns true if the TraceState does not contain any entries +func (ts TraceState) IsEmpty() bool { + return len(ts.kvs) == 0 +} + +func (ts TraceState) copyKVsAndDeleteEntry(key attribute.Key) []attribute.KeyValue { + ckvs := make([]attribute.KeyValue, len(ts.kvs)) + copy(ckvs, ts.kvs) + for i, kv := range ts.kvs { + if kv.Key == key { + ckvs = append(ckvs[:i], ckvs[i+1:]...) + break + } + } + + return ckvs +} + +// TraceStateFromKeyValues is a convenience method to create a new TraceState from +// provided key/value pairs. +func TraceStateFromKeyValues(kvs ...attribute.KeyValue) (TraceState, error) { //nolint:golint + if len(kvs) == 0 { + return TraceState{}, nil + } + + if len(kvs) > traceStateMaxListMembers { + return TraceState{}, errInvalidTraceStateMembersNumber + } + + km := make(map[attribute.Key]bool) + for _, kv := range kvs { + if !isTraceStateKeyValueValid(kv) { + return TraceState{}, errInvalidTraceStateKeyValue + } + _, ok := km[kv.Key] + if ok { + return TraceState{}, errInvalidTraceStateDuplicate + } + km[kv.Key] = true + } + + ckvs := make([]attribute.KeyValue, len(kvs)) + copy(ckvs, kvs) + return TraceState{ckvs}, nil +} + +func isTraceStateKeyValid(key attribute.Key) bool { + return keyFormatRegExp.MatchString(string(key)) +} + +func isTraceStateKeyValueValid(kv attribute.KeyValue) bool { + return isTraceStateKeyValid(kv.Key) && + valueFormatRegExp.MatchString(kv.Value.Emit()) +} + +// TraceFlags contains flags that can be set on a SpanContext +type TraceFlags byte //nolint:golint + +// IsSampled returns if the sampling bit is set in the TraceFlags. +func (tf TraceFlags) IsSampled() bool { + return tf&FlagsSampled == FlagsSampled +} + +// WithSampled sets the sampling bit in a new copy of the TraceFlags. +func (tf TraceFlags) WithSampled(sampled bool) TraceFlags { + if sampled { + return tf | FlagsSampled + } + + return tf &^ FlagsSampled +} + +// MarshalJSON implements a custom marshal function to encode TraceFlags +// as a hex string. +func (tf TraceFlags) MarshalJSON() ([]byte, error) { + return json.Marshal(tf.String()) +} + +// String returns the hex string representation form of TraceFlags +func (tf TraceFlags) String() string { + return hex.EncodeToString([]byte{byte(tf)}[:]) +} + +// SpanContextConfig contains mutable fields usable for constructing +// an immutable SpanContext. +type SpanContextConfig struct { + TraceID TraceID + SpanID SpanID + TraceFlags TraceFlags + TraceState TraceState + Remote bool +} + +// NewSpanContext constructs a SpanContext using values from the provided +// SpanContextConfig. +func NewSpanContext(config SpanContextConfig) SpanContext { + return SpanContext{ + traceID: config.TraceID, + spanID: config.SpanID, + traceFlags: config.TraceFlags, + traceState: config.TraceState, + remote: config.Remote, + } +} + +// SpanContext contains identifying trace information about a Span. +type SpanContext struct { + traceID TraceID + spanID SpanID + traceFlags TraceFlags + traceState TraceState + remote bool +} + +// IsValid returns if the SpanContext is valid. A valid span context has a +// valid TraceID and SpanID. +func (sc SpanContext) IsValid() bool { + return sc.HasTraceID() && sc.HasSpanID() +} + +// IsRemote indicates whether the SpanContext represents a remotely-created Span. +func (sc SpanContext) IsRemote() bool { + return sc.remote +} + +// WithRemote returns a copy of sc with the Remote property set to remote. +func (sc SpanContext) WithRemote(remote bool) SpanContext { + return SpanContext{ + traceID: sc.traceID, + spanID: sc.spanID, + traceFlags: sc.traceFlags, + traceState: sc.traceState, + remote: remote, + } +} + +// TraceID returns the TraceID from the SpanContext. +func (sc SpanContext) TraceID() TraceID { + return sc.traceID +} + +// HasTraceID checks if the SpanContext has a valid TraceID. +func (sc SpanContext) HasTraceID() bool { + return sc.traceID.IsValid() +} + +// WithTraceID returns a new SpanContext with the TraceID replaced. +func (sc SpanContext) WithTraceID(traceID TraceID) SpanContext { + return SpanContext{ + traceID: traceID, + spanID: sc.spanID, + traceFlags: sc.traceFlags, + traceState: sc.traceState, + remote: sc.remote, + } +} + +// SpanID returns the SpanID from the SpanContext. +func (sc SpanContext) SpanID() SpanID { + return sc.spanID +} + +// HasSpanID checks if the SpanContext has a valid SpanID. +func (sc SpanContext) HasSpanID() bool { + return sc.spanID.IsValid() +} + +// WithSpanID returns a new SpanContext with the SpanID replaced. +func (sc SpanContext) WithSpanID(spanID SpanID) SpanContext { + return SpanContext{ + traceID: sc.traceID, + spanID: spanID, + traceFlags: sc.traceFlags, + traceState: sc.traceState, + remote: sc.remote, + } +} + +// TraceFlags returns the flags from the SpanContext. +func (sc SpanContext) TraceFlags() TraceFlags { + return sc.traceFlags +} + +// IsSampled returns if the sampling bit is set in the SpanContext's TraceFlags. +func (sc SpanContext) IsSampled() bool { + return sc.traceFlags.IsSampled() +} + +// WithTraceFlags returns a new SpanContext with the TraceFlags replaced. +func (sc SpanContext) WithTraceFlags(flags TraceFlags) SpanContext { + return SpanContext{ + traceID: sc.traceID, + spanID: sc.spanID, + traceFlags: flags, + traceState: sc.traceState, + remote: sc.remote, + } +} + +// TraceState returns the TraceState from the SpanContext. +func (sc SpanContext) TraceState() TraceState { + return sc.traceState +} + +// WithTraceState returns a new SpanContext with the TraceState replaced. +func (sc SpanContext) WithTraceState(state TraceState) SpanContext { + return SpanContext{ + traceID: sc.traceID, + spanID: sc.spanID, + traceFlags: sc.traceFlags, + traceState: state, + remote: sc.remote, + } +} + +// Equal is a predicate that determines whether two SpanContext values are equal. +func (sc SpanContext) Equal(other SpanContext) bool { + return sc.traceID == other.traceID && + sc.spanID == other.spanID && + sc.traceFlags == other.traceFlags && + sc.traceState.String() == other.traceState.String() && + sc.remote == other.remote +} + +// MarshalJSON implements a custom marshal function to encode a SpanContext. +func (sc SpanContext) MarshalJSON() ([]byte, error) { + return json.Marshal(SpanContextConfig{ + TraceID: sc.traceID, + SpanID: sc.spanID, + TraceFlags: sc.traceFlags, + TraceState: sc.traceState, + Remote: sc.remote, + }) +} + +// Span is the individual component of a trace. It represents a single named +// and timed operation of a workflow that is traced. A Tracer is used to +// create a Span and it is then up to the operation the Span represents to +// properly end the Span when the operation itself ends. +type Span interface { + // Tracer returns the Tracer that created the Span. Tracer MUST NOT be + // nil. + Tracer() Tracer + + // End completes the Span. The Span is considered complete and ready to be + // delivered through the rest of the telemetry pipeline after this method + // is called. Therefore, updates to the Span are not allowed after this + // method has been called. + End(options ...SpanOption) + + // AddEvent adds an event with the provided name and options. + AddEvent(name string, options ...EventOption) + + // IsRecording returns the recording state of the Span. It will return + // true if the Span is active and events can be recorded. + IsRecording() bool + + // RecordError will record err as an exception span event for this span. An + // additional call toSetStatus is required if the Status of the Span should + // be set to Error, this method does not change the Span status. If this + // span is not being recorded or err is nil than this method does nothing. + RecordError(err error, options ...EventOption) + + // SpanContext returns the SpanContext of the Span. The returned + // SpanContext is usable even after the End has been called for the Span. + SpanContext() SpanContext + + // SetStatus sets the status of the Span in the form of a code and a + // message. SetStatus overrides the value of previous calls to SetStatus + // on the Span. + SetStatus(code codes.Code, msg string) + + // SetName sets the Span name. + SetName(name string) + + // SetAttributes sets kv as attributes of the Span. If a key from kv + // already exists for an attribute of the Span it will be overwritten with + // the value contained in kv. + SetAttributes(kv ...attribute.KeyValue) +} + +// Event is a thing that happened during a Span's lifetime. +type Event struct { + // Name is the name of this event + Name string + + // Attributes describe the aspects of the event. + Attributes []attribute.KeyValue + + // DroppedAttributeCount is the number of attributes that were not + // recorded due to configured limits being reached. + DroppedAttributeCount int + + // Time at which this event was recorded. + Time time.Time +} + +// Link is the relationship between two Spans. The relationship can be within +// the same Trace or across different Traces. +// +// For example, a Link is used in the following situations: +// +// 1. Batch Processing: A batch of operations may contain operations +// associated with one or more traces/spans. Since there can only be one +// parent SpanContext, a Link is used to keep reference to the +// SpanContext of all operations in the batch. +// 2. Public Endpoint: A SpanContext for an in incoming client request on a +// public endpoint should be considered untrusted. In such a case, a new +// trace with its own identity and sampling decision needs to be created, +// but this new trace needs to be related to the original trace in some +// form. A Link is used to keep reference to the original SpanContext and +// track the relationship. +type Link struct { + // SpanContext of the linked Span. + SpanContext + + // Attributes describe the aspects of the link. + Attributes []attribute.KeyValue + + // DroppedAttributeCount is the number of attributes that were not + // recorded due to configured limits being reached. + DroppedAttributeCount int +} + +// SpanKind is the role a Span plays in a Trace. +type SpanKind int + +// As a convenience, these match the proto definition, see +// https://github.com/open-telemetry/opentelemetry-proto/blob/30d237e1ff3ab7aa50e0922b5bebdd93505090af/opentelemetry/proto/trace/v1/trace.proto#L101-L129 +// +// The unspecified value is not a valid `SpanKind`. Use `ValidateSpanKind()` +// to coerce a span kind to a valid value. +const ( + // SpanKindUnspecified is an unspecified SpanKind and is not a valid + // SpanKind. SpanKindUnspecified should be replaced with SpanKindInternal + // if it is received. + SpanKindUnspecified SpanKind = 0 + // SpanKindInternal is a SpanKind for a Span that represents an internal + // operation within an application. + SpanKindInternal SpanKind = 1 + // SpanKindServer is a SpanKind for a Span that represents the operation + // of handling a request from a client. + SpanKindServer SpanKind = 2 + // SpanKindClient is a SpanKind for a Span that represents the operation + // of client making a request to a server. + SpanKindClient SpanKind = 3 + // SpanKindProducer is a SpanKind for a Span that represents the operation + // of a producer sending a message to a message broker. Unlike + // SpanKindClient and SpanKindServer, there is often no direct + // relationship between this kind of Span and a SpanKindConsumer kind. A + // SpanKindProducer Span will end once the message is accepted by the + // message broker which might not overlap with the processing of that + // message. + SpanKindProducer SpanKind = 4 + // SpanKindConsumer is a SpanKind for a Span that represents the operation + // of a consumer receiving a message from a message broker. Like + // SpanKindProducer Spans, there is often no direct relationship between + // this Span and the Span that produced the message. + SpanKindConsumer SpanKind = 5 +) + +// ValidateSpanKind returns a valid span kind value. This will coerce +// invalid values into the default value, SpanKindInternal. +func ValidateSpanKind(spanKind SpanKind) SpanKind { + switch spanKind { + case SpanKindInternal, + SpanKindServer, + SpanKindClient, + SpanKindProducer, + SpanKindConsumer: + // valid + return spanKind + default: + return SpanKindInternal + } +} + +// String returns the specified name of the SpanKind in lower-case. +func (sk SpanKind) String() string { + switch sk { + case SpanKindInternal: + return "internal" + case SpanKindServer: + return "server" + case SpanKindClient: + return "client" + case SpanKindProducer: + return "producer" + case SpanKindConsumer: + return "consumer" + default: + return "unspecified" + } +} + +// Tracer is the creator of Spans. +type Tracer interface { + // Start creates a span. + Start(ctx context.Context, spanName string, opts ...SpanOption) (context.Context, Span) +} + +// TracerProvider provides access to instrumentation Tracers. +type TracerProvider interface { + // Tracer creates an implementation of the Tracer interface. + // The instrumentationName must be the name of the library providing + // instrumentation. This name may be the same as the instrumented code + // only if that code provides built-in instrumentation. If the + // instrumentationName is empty, then a implementation defined default + // name will be used instead. + // + // This method must be concurrency safe. + Tracer(instrumentationName string, opts ...TracerOption) Tracer +} diff --git a/vendor/go.opentelemetry.io/otel/api/unit/doc.go b/vendor/go.opentelemetry.io/otel/unit/doc.go similarity index 65% rename from vendor/go.opentelemetry.io/otel/api/unit/doc.go rename to vendor/go.opentelemetry.io/otel/unit/doc.go index f03ed5595031..0d77a750cc32 100644 --- a/vendor/go.opentelemetry.io/otel/api/unit/doc.go +++ b/vendor/go.opentelemetry.io/otel/unit/doc.go @@ -12,4 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -package unit // import "go.opentelemetry.io/otel/api/unit" +// Package unit provides units. +// +// This package is currently in a pre-GA phase. Backwards incompatible changes +// may be introduced in subsequent minor version releases as we work to track +// the evolving OpenTelemetry specification and user feedback. +package unit // import "go.opentelemetry.io/otel/unit" diff --git a/vendor/go.opentelemetry.io/otel/api/unit/unit.go b/vendor/go.opentelemetry.io/otel/unit/unit.go similarity index 92% rename from vendor/go.opentelemetry.io/otel/api/unit/unit.go rename to vendor/go.opentelemetry.io/otel/unit/unit.go index dcd39af028da..523bfe1d0a12 100644 --- a/vendor/go.opentelemetry.io/otel/api/unit/unit.go +++ b/vendor/go.opentelemetry.io/otel/unit/unit.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package unit +package unit // import "go.opentelemetry.io/otel/unit" type Unit string diff --git a/vendor/go.opentelemetry.io/otel/label/doc.go b/vendor/go.opentelemetry.io/otel/version.go similarity index 78% rename from vendor/go.opentelemetry.io/otel/label/doc.go rename to vendor/go.opentelemetry.io/otel/version.go index d631d23871ef..81be6f368172 100644 --- a/vendor/go.opentelemetry.io/otel/label/doc.go +++ b/vendor/go.opentelemetry.io/otel/version.go @@ -12,5 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package label provides key and value labels. -package label // import "go.opentelemetry.io/otel/label" +package otel // import "go.opentelemetry.io/otel" + +// Version is the current release version of OpenTelemetry in use. +func Version() string { + return "0.20.0" +} diff --git a/vendor/golang.org/x/net/http2/ascii.go b/vendor/golang.org/x/net/http2/ascii.go new file mode 100644 index 000000000000..0c58d727c174 --- /dev/null +++ b/vendor/golang.org/x/net/http2/ascii.go @@ -0,0 +1,49 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import "strings" + +// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t +// are equal, ASCII-case-insensitively. +func asciiEqualFold(s, t string) bool { + if len(s) != len(t) { + return false + } + for i := 0; i < len(s); i++ { + if lower(s[i]) != lower(t[i]) { + return false + } + } + return true +} + +// lower returns the ASCII lowercase version of b. +func lower(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// isASCIIPrint returns whether s is ASCII and printable according to +// https://tools.ietf.org/html/rfc20#section-4.2. +func isASCIIPrint(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] < ' ' || s[i] > '~' { + return false + } + } + return true +} + +// asciiToLower returns the lowercase version of s if s is ASCII and printable, +// and whether or not it was. +func asciiToLower(s string) (lower string, ok bool) { + if !isASCIIPrint(s) { + return "", false + } + return strings.ToLower(s), true +} diff --git a/vendor/golang.org/x/net/http2/headermap.go b/vendor/golang.org/x/net/http2/headermap.go index c3ff3fa1c78c..9e12941da4c3 100644 --- a/vendor/golang.org/x/net/http2/headermap.go +++ b/vendor/golang.org/x/net/http2/headermap.go @@ -6,7 +6,6 @@ package http2 import ( "net/http" - "strings" "sync" ) @@ -79,10 +78,10 @@ func buildCommonHeaderMaps() { } } -func lowerHeader(v string) string { +func lowerHeader(v string) (lower string, ascii bool) { buildCommonHeaderMapsOnce() if s, ok := commonLowerHeader[v]; ok { - return s + return s, true } - return strings.ToLower(v) + return asciiToLower(v) } diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go index e125bbd2a264..09bc70533a8b 100644 --- a/vendor/golang.org/x/net/http2/server.go +++ b/vendor/golang.org/x/net/http2/server.go @@ -231,13 +231,12 @@ func ConfigureServer(s *http.Server, conf *Server) error { if s.TLSConfig == nil { s.TLSConfig = new(tls.Config) - } else if s.TLSConfig.CipherSuites != nil { - // If they already provided a CipherSuite list, return - // an error if it has a bad order or is missing - // ECDHE_RSA_WITH_AES_128_GCM_SHA256 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. + } else if s.TLSConfig.CipherSuites != nil && s.TLSConfig.MinVersion < tls.VersionTLS13 { + // If they already provided a TLS 1.0–1.2 CipherSuite list, return an + // error if it is missing ECDHE_RSA_WITH_AES_128_GCM_SHA256 or + // ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. haveRequired := false - sawBad := false - for i, cs := range s.TLSConfig.CipherSuites { + for _, cs := range s.TLSConfig.CipherSuites { switch cs { case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // Alternative MTI cipher to not discourage ECDSA-only servers. @@ -245,14 +244,9 @@ func ConfigureServer(s *http.Server, conf *Server) error { tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: haveRequired = true } - if isBadCipher(cs) { - sawBad = true - } else if sawBad { - return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs) - } } if !haveRequired { - return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).") + return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)") } } @@ -2789,8 +2783,12 @@ func (w *responseWriter) Push(target string, opts *http.PushOptions) error { // but PUSH_PROMISE requests cannot have a body. // http://tools.ietf.org/html/rfc7540#section-8.2 // Also disallow Host, since the promised URL must be absolute. - switch strings.ToLower(k) { - case "content-length", "content-encoding", "trailer", "te", "expect", "host": + if asciiEqualFold(k, "content-length") || + asciiEqualFold(k, "content-encoding") || + asciiEqualFold(k, "trailer") || + asciiEqualFold(k, "te") || + asciiEqualFold(k, "expect") || + asciiEqualFold(k, "host") { return fmt.Errorf("promised request headers cannot include %q", k) } } diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index f89369e30620..7bd4b9c19716 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -995,7 +995,7 @@ func checkConnHeaders(req *http.Request) error { if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") { return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv) } - if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !strings.EqualFold(vv[0], "close") && !strings.EqualFold(vv[0], "keep-alive")) { + if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !asciiEqualFold(vv[0], "close") && !asciiEqualFold(vv[0], "keep-alive")) { return fmt.Errorf("http2: invalid Connection request header: %q", vv) } return nil @@ -1521,19 +1521,21 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail var didUA bool for k, vv := range req.Header { - if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") { + if asciiEqualFold(k, "host") || asciiEqualFold(k, "content-length") { // Host is :authority, already sent. // Content-Length is automatic, set below. continue - } else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") || - strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") || - strings.EqualFold(k, "keep-alive") { + } else if asciiEqualFold(k, "connection") || + asciiEqualFold(k, "proxy-connection") || + asciiEqualFold(k, "transfer-encoding") || + asciiEqualFold(k, "upgrade") || + asciiEqualFold(k, "keep-alive") { // Per 8.1.2.2 Connection-Specific Header // Fields, don't send connection-specific // fields. We have already checked if any // are error-worthy so just ignore the rest. continue - } else if strings.EqualFold(k, "user-agent") { + } else if asciiEqualFold(k, "user-agent") { // Match Go's http1 behavior: at most one // User-Agent. If set to nil or empty string, // then omit it. Otherwise if not mentioned, @@ -1546,7 +1548,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail if vv[0] == "" { continue } - } else if strings.EqualFold(k, "cookie") { + } else if asciiEqualFold(k, "cookie") { // Per 8.1.2.5 To allow for better compression efficiency, the // Cookie header field MAY be split into separate header fields, // each with one or more cookie-pairs. @@ -1605,7 +1607,12 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail // Header list size is ok. Write the headers. enumerateHeaders(func(name, value string) { - name = strings.ToLower(name) + name, ascii := asciiToLower(name) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + return + } cc.writeHeader(name, value) if traceHeaders { traceWroteHeaderField(trace, name, value) @@ -1653,9 +1660,14 @@ func (cc *ClientConn) encodeTrailers(req *http.Request) ([]byte, error) { } for k, vv := range req.Trailer { + lowKey, ascii := asciiToLower(k) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + continue + } // Transfer-Encoding, etc.. have already been filtered at the // start of RoundTrip - lowKey := strings.ToLower(k) for _, v := range vv { cc.writeHeader(lowKey, v) } diff --git a/vendor/golang.org/x/net/http2/write.go b/vendor/golang.org/x/net/http2/write.go index 3849bc2632ef..33f61398a123 100644 --- a/vendor/golang.org/x/net/http2/write.go +++ b/vendor/golang.org/x/net/http2/write.go @@ -341,7 +341,12 @@ func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) { } for _, k := range keys { vv := h[k] - k = lowerHeader(k) + k, ascii := lowerHeader(k) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + continue + } if !validWireHeaderFieldName(k) { // Skip it as backup paranoia. Per // golang.org/issue/14048, these should diff --git a/vendor/modules.txt b/vendor/modules.txt index 9122692cde4a..c821872fe789 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -179,7 +179,7 @@ github.com/coreos/go-systemd/internal/dlopen github.com/coreos/go-systemd/sdjournal # github.com/coreos/go-systemd/v22 v22.1.0 github.com/coreos/go-systemd/v22/journal -# github.com/cortexproject/cortex v1.9.1-0.20210527130655-bd720c688ffa +# github.com/cortexproject/cortex v1.9.1-0.20210712083557-733f7de5c81f ## explicit github.com/cortexproject/cortex/pkg/alertmanager github.com/cortexproject/cortex/pkg/alertmanager/alertmanagerpb @@ -409,7 +409,7 @@ github.com/go-openapi/jsonpointer github.com/go-openapi/jsonreference # github.com/go-openapi/loads v0.20.2 github.com/go-openapi/loads -# github.com/go-openapi/runtime v0.19.26 +# github.com/go-openapi/runtime v0.19.28 github.com/go-openapi/runtime github.com/go-openapi/runtime/flagext github.com/go-openapi/runtime/logger @@ -422,14 +422,15 @@ github.com/go-openapi/runtime/security github.com/go-openapi/spec # github.com/go-openapi/strfmt v0.20.1 github.com/go-openapi/strfmt -# github.com/go-openapi/swag v0.19.14 +# github.com/go-openapi/swag v0.19.15 github.com/go-openapi/swag # github.com/go-openapi/validate v0.20.2 github.com/go-openapi/validate -# github.com/go-redis/redis/v8 v8.2.3 +# github.com/go-redis/redis/v8 v8.9.0 github.com/go-redis/redis/v8 github.com/go-redis/redis/v8/internal github.com/go-redis/redis/v8/internal/hashtag +github.com/go-redis/redis/v8/internal/hscan github.com/go-redis/redis/v8/internal/pool github.com/go-redis/redis/v8/internal/proto github.com/go-redis/redis/v8/internal/rand @@ -575,7 +576,7 @@ github.com/hashicorp/go-sockaddr ## explicit github.com/hashicorp/golang-lru github.com/hashicorp/golang-lru/simplelru -# github.com/hashicorp/memberlist v0.2.2 +# github.com/hashicorp/memberlist v0.2.3 github.com/hashicorp/memberlist # github.com/hashicorp/serf v0.9.5 github.com/hashicorp/serf/coordinate @@ -602,7 +603,7 @@ github.com/influxdata/go-syslog/v3/rfc5424 ## explicit github.com/influxdata/telegraf github.com/influxdata/telegraf/plugins/inputs -# github.com/jessevdk/go-flags v1.4.0 +# github.com/jessevdk/go-flags v1.5.0 github.com/jessevdk/go-flags # github.com/jmespath/go-jmespath v0.4.0 ## explicit @@ -734,7 +735,7 @@ github.com/pierrec/lz4/v4/internal/xxh32 github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib -# github.com/prometheus/alertmanager v0.21.1-0.20210422101724-8176f78a70e1 +# github.com/prometheus/alertmanager v0.22.1-0.20210603124511-8b584eb2265e github.com/prometheus/alertmanager/api github.com/prometheus/alertmanager/api/metrics github.com/prometheus/alertmanager/api/v1 @@ -788,7 +789,7 @@ github.com/prometheus/client_golang/prometheus/testutil/promlint # github.com/prometheus/client_model v0.2.0 ## explicit github.com/prometheus/client_model/go -# github.com/prometheus/common v0.23.0 +# github.com/prometheus/common v0.26.1-0.20210603143733-6ef301f414bf ## explicit github.com/prometheus/common/config github.com/prometheus/common/expfmt @@ -1109,19 +1110,23 @@ go.opencensus.io/trace go.opencensus.io/trace/internal go.opencensus.io/trace/propagation go.opencensus.io/trace/tracestate -# go.opentelemetry.io/otel v0.11.0 +# go.opentelemetry.io/otel v0.20.0 go.opentelemetry.io/otel -go.opentelemetry.io/otel/api/correlation -go.opentelemetry.io/otel/api/global -go.opentelemetry.io/otel/api/global/internal -go.opentelemetry.io/otel/api/metric -go.opentelemetry.io/otel/api/metric/registry -go.opentelemetry.io/otel/api/propagation -go.opentelemetry.io/otel/api/trace -go.opentelemetry.io/otel/api/unit +go.opentelemetry.io/otel/attribute go.opentelemetry.io/otel/codes go.opentelemetry.io/otel/internal -go.opentelemetry.io/otel/label +go.opentelemetry.io/otel/internal/baggage +go.opentelemetry.io/otel/internal/global +go.opentelemetry.io/otel/internal/trace/noop +go.opentelemetry.io/otel/propagation +go.opentelemetry.io/otel/unit +# go.opentelemetry.io/otel/metric v0.20.0 +go.opentelemetry.io/otel/metric +go.opentelemetry.io/otel/metric/global +go.opentelemetry.io/otel/metric/number +go.opentelemetry.io/otel/metric/registry +# go.opentelemetry.io/otel/trace v0.20.0 +go.opentelemetry.io/otel/trace # go.uber.org/atomic v1.7.0 ## explicit go.uber.org/atomic @@ -1155,7 +1160,7 @@ golang.org/x/lint/golint # golang.org/x/mod v0.4.1 golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.0.0-20210505214959-0714010a04ed +# golang.org/x/net v0.0.0-20210525063256-abc453219eb5 ## explicit golang.org/x/net/bpf golang.org/x/net/context @@ -1175,7 +1180,7 @@ golang.org/x/net/netutil golang.org/x/net/proxy golang.org/x/net/publicsuffix golang.org/x/net/trace -# golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c +# golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c golang.org/x/oauth2 golang.org/x/oauth2/authhandler golang.org/x/oauth2/clientcredentials From 43bcd92868e668d4c690b0e6d82a2929c1254cc3 Mon Sep 17 00:00:00 2001 From: Michel Hollands Date: Tue, 13 Jul 2021 15:18:52 +0100 Subject: [PATCH 2/3] Changed code due to new Cortex version Signed-off-by: Michel Hollands --- pkg/distributor/distributor_test.go | 4 ++++ pkg/loki/loki.go | 2 +- pkg/querier/querier_mock_test.go | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/distributor/distributor_test.go b/pkg/distributor/distributor_test.go index 69e0272fb611..d7dfe2220a54 100644 --- a/pkg/distributor/distributor_test.go +++ b/pkg/distributor/distributor_test.go @@ -424,3 +424,7 @@ func (r mockRing) ShuffleShardWithLookback(identifier string, size int, lookback } func (r mockRing) CleanupShuffleShardCache(identifier string) {} + +func (r mockRing) GetInstanceState(instanceID string) (ring.InstanceState, error) { + return 0, nil +} diff --git a/pkg/loki/loki.go b/pkg/loki/loki.go index 1d116682d2e2..060e3bb82f85 100644 --- a/pkg/loki/loki.go +++ b/pkg/loki/loki.go @@ -101,7 +101,7 @@ func (c *Config) RegisterFlags(f *flag.FlagSet) { c.Worker.RegisterFlags(f) c.QueryRange.RegisterFlags(f) c.RuntimeConfig.RegisterFlags(f) - c.MemberlistKV.RegisterFlags(f, "") + c.MemberlistKV.RegisterFlags(f) c.Tracing.RegisterFlags(f) c.CompactorConfig.RegisterFlags(f) } diff --git a/pkg/querier/querier_mock_test.go b/pkg/querier/querier_mock_test.go index e13bda18a8c7..2d9a5bd52325 100644 --- a/pkg/querier/querier_mock_test.go +++ b/pkg/querier/querier_mock_test.go @@ -356,6 +356,10 @@ func (r *readRingMock) ShuffleShardWithLookback(identifier string, size int, loo func (r *readRingMock) CleanupShuffleShardCache(identifier string) {} +func (r *readRingMock) GetInstanceState(instanceID string) (ring.InstanceState, error) { + return 0, nil +} + func mockReadRingWithOneActiveIngester() *readRingMock { return newReadRingMock([]ring.InstanceDesc{ {Addr: "test", Timestamp: time.Now().UnixNano(), State: ring.ACTIVE, Tokens: []uint32{1, 2, 3}}, From f9d10d8170aa1dc1b711abf39c4c7868bc6b00a6 Mon Sep 17 00:00:00 2001 From: Michel Hollands Date: Tue, 13 Jul 2021 15:26:35 +0100 Subject: [PATCH 3/3] Run go mod tidy Signed-off-by: Michel Hollands --- go.sum | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/go.sum b/go.sum index fea8edfb2145..a49d7c840206 100644 --- a/go.sum +++ b/go.sum @@ -347,8 +347,6 @@ github.com/cortexproject/cortex v1.6.1-0.20210215155036-dfededd9f331/go.mod h1:8 github.com/cortexproject/cortex v1.7.1-0.20210224085859-66d6fb5b0d42/go.mod h1:u2dxcHInYbe45wxhLoWVdlFJyDhXewsMcxtnbq/QbH4= github.com/cortexproject/cortex v1.7.1-0.20210316085356-3fedc1108a49/go.mod h1:/DBOW8TzYBTE/U+O7Whs7i7E2eeeZl1iRVDtIqxn5kg= github.com/cortexproject/cortex v1.8.1-0.20210422151339-cf1c444e0905/go.mod h1:xxm4/CLvTmDxwE7yXwtClR4dIvkG4S09o5DygPOgc1U= -github.com/cortexproject/cortex v1.9.1-0.20210527130655-bd720c688ffa h1:Z9Mi0HskMjHb606OFa89kv7hyfIVcriis0Ssh9WrbyM= -github.com/cortexproject/cortex v1.9.1-0.20210527130655-bd720c688ffa/go.mod h1:aHcimX/nX9yUmk2iOWeQrE3hTh3gqIe6QOOo/6RkBlU= github.com/cortexproject/cortex v1.9.1-0.20210712083557-733f7de5c81f h1:+77Qgcyyz7iwlZd+m9n5c/4Zw5CSn5IwC7wV2xDIVV4= github.com/cortexproject/cortex v1.9.1-0.20210712083557-733f7de5c81f/go.mod h1:I9ew9PB8l8+YI+Qq85XJ2wEkAg8y8dAX1z/g6SFZ8g0= github.com/couchbase/go-couchbase v0.0.0-20180501122049-16db1f1fe037/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= @@ -512,6 +510,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -585,7 +584,6 @@ github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29g github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= -github.com/go-openapi/runtime v0.19.26 h1:K/6PoVNj5WJXUnMk+VEbELeXjtBkCS1UxTDa04tdXE0= github.com/go-openapi/runtime v0.19.26/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= github.com/go-openapi/runtime v0.19.28 h1:9lYu6axek8LJrVkMVViVirRcpoaCxXX7+sSvmizGVnA= github.com/go-openapi/runtime v0.19.28/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= @@ -628,7 +626,6 @@ github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfT github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= @@ -647,7 +644,6 @@ github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZ github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.0.0-beta.10.0.20200905143926-df7fe4e2ce72/go.mod h1:CJP1ZIHwhosNYwIdaHPZK9vHsM3+roNBaZ7U9Of1DXc= -github.com/go-redis/redis/v8 v8.2.3 h1:eNesND+DWt/sjQOtPFxAbQkTIXaXX00qNLxjVWkZ70k= github.com/go-redis/redis/v8 v8.2.3/go.mod h1:ysgGY09J/QeDYbu3HikWEIPCwaeOkuNoTgKayTEaEOw= github.com/go-redis/redis/v8 v8.9.0 h1:FTTbB7WqlXfVNdVv0SsxA+oVi0bAwit6bMe3IUucq2o= github.com/go-redis/redis/v8 v8.9.0/go.mod h1:ik7vb7+gm8Izylxu6kf6wG26/t2VljgCfSQ1DM4O1uU= @@ -964,7 +960,6 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.2.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.2.3 h1:BwZa5IjREr75J0am7nblP+X5i95Rmp8EEbMI5vkUWdA= github.com/hashicorp/memberlist v0.2.3/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= @@ -1032,7 +1027,6 @@ github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9de github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee/go.mod h1:N0t2vlmpe8nyZB5ouIbJQPDSR+mH6oe7xHB9VZHSUzM= github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= @@ -1304,8 +1298,8 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -1315,8 +1309,8 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/openconfig/gnmi v0.0.0-20180912164834-33a1865c3029/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= @@ -1386,7 +1380,6 @@ github.com/prometheus/alertmanager v0.21.0/go.mod h1:h7tJ81NA0VLWvWEayi1QltevFkL github.com/prometheus/alertmanager v0.21.1-0.20200911160112-1fdff6b3f939/go.mod h1:imXRHOP6QTsE0fFsIsAV/cXimS32m7gVZOiUj11m6Ig= github.com/prometheus/alertmanager v0.21.1-0.20201106142418-c39b78780054/go.mod h1:imXRHOP6QTsE0fFsIsAV/cXimS32m7gVZOiUj11m6Ig= github.com/prometheus/alertmanager v0.21.1-0.20210310093010-0f9cab6991e6/go.mod h1:MTqVn+vIupE0dzdgo+sMcNCp37SCAi8vPrvKTTnTz9g= -github.com/prometheus/alertmanager v0.21.1-0.20210422101724-8176f78a70e1 h1:i7S+d1wua/WE/ipFcX2hSUN6Fqn+8+pMQPjFTBxGWFE= github.com/prometheus/alertmanager v0.21.1-0.20210422101724-8176f78a70e1/go.mod h1:gsEqwD5BHHW9RNKvCuPOrrTMiP5I+faJUyLXvnivHik= github.com/prometheus/alertmanager v0.22.1-0.20210603124511-8b584eb2265e h1:FNLZCG1rR9QPbkwYLMiy7TnI4WRB7TeipcxkrbszN4E= github.com/prometheus/alertmanager v0.22.1-0.20210603124511-8b584eb2265e/go.mod h1:ntrorfzWQ1I9mhJK7AO71w4xMUgM4SxmwbtyQgAWZz0= @@ -1439,7 +1432,6 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.20.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.21.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.23.0 h1:GXWvPYuTUenIa+BhOq/x+L/QZzCqASkVRny5KTlPDGM= github.com/prometheus/common v0.23.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= github.com/prometheus/common v0.24.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= github.com/prometheus/common v0.26.1-0.20210603143733-6ef301f414bf h1:w+U3wF/6JRY6+MNfxTodIBw6dZaE11Y+Arg3bRLqatI= @@ -1754,12 +1746,12 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E= go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0= go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= @@ -1934,7 +1926,6 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210324051636-2c4c8ecb7826/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210505214959-0714010a04ed h1:V9kAVxLvz1lkufatrpHuUVyJ/5tR3Ms7rk951P4mI98= golang.org/x/net v0.0.0-20210505214959-0714010a04ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1954,7 +1945,6 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c h1:SgVl/sCtkicsS7psKkje4H9YtjdEl3xsYh7N+5TDHqY= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=