From c43e21c24d3e90dcd33621c5b4185ac66dcc17f0 Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Fri, 6 Mar 2020 11:58:29 +0100 Subject: [PATCH 1/4] Upgraded Thanos to 0.11.0 and switched to binary index header Signed-off-by: Marco Pracucci --- CHANGELOG.md | 1 + docs/configuration/config-file-reference.md | 11 + docs/operations/blocks-storage.md | 11 + go.mod | 7 +- go.sum | 46 +- integration/querier_test.go | 10 - pkg/alertmanager/alertmanager.go | 11 +- pkg/compactor/compactor.go | 9 +- pkg/compactor/compactor_test.go | 8 + pkg/compactor/syncer_metrics.go | 7 + pkg/compactor/syncer_metrics_test.go | 11 + pkg/ingester/metrics.go | 6 +- pkg/ingester/metrics_test.go | 12 +- pkg/querier/block_store.go | 26 +- pkg/querier/block_store_metrics.go | 46 +- pkg/querier/bucket_store_metrics_test.go | 58 +- pkg/storage/tsdb/config.go | 4 + pkg/util/metrics_helper.go | 40 + pkg/util/metrics_helper_test.go | 56 ++ .../github.com/go-openapi/runtime/request.go | 64 +- .../runtime/security/authenticator.go | 18 +- vendor/github.com/go-openapi/swag/yaml.go | 47 +- vendor/github.com/minio/minio-go/v6/README.md | 5 + .../minio/minio-go/v6/api-compose-object.go | 100 ++- .../minio/minio-go/v6/api-error-response.go | 4 + .../minio-go/v6/api-get-bucket-encryption.go | 71 ++ .../minio/minio-go/v6/api-get-object.go | 21 +- .../github.com/minio/minio-go/v6/api-list.go | 23 +- .../minio/minio-go/v6/api-notification.go | 14 +- .../minio-go/v6/api-object-legal-hold.go | 176 ++++ .../minio/minio-go/v6/api-object-tagging.go | 163 ++++ .../minio/minio-go/v6/api-put-bucket.go | 97 +- .../minio-go/v6/api-put-object-common.go | 16 +- .../minio/minio-go/v6/api-put-object-copy.go | 10 +- .../minio-go/v6/api-put-object-multipart.go | 10 +- .../minio-go/v6/api-put-object-streaming.go | 35 +- .../minio/minio-go/v6/api-put-object.go | 22 +- .../minio/minio-go/v6/api-s3-datatypes.go | 16 + .../github.com/minio/minio-go/v6/api-stat.go | 7 +- vendor/github.com/minio/minio-go/v6/api.go | 35 +- .../minio/minio-go/v6/bucket-cache.go | 4 + .../github.com/minio/minio-go/v6/constants.go | 5 + .../minio-go/v6/pkg/credentials/iam_aws.go | 109 ++- .../v6/pkg/credentials/sts_web_identity.go | 24 +- .../minio-go/v6/pkg/encrypt/server-side.go | 4 +- .../minio/minio-go/v6/pkg/s3utils/utils.go | 49 +- .../minio/minio-go/v6/post-policy.go | 21 + vendor/github.com/minio/minio-go/v6/retry.go | 37 - .../minio/minio-go/v6/s3-endpoints.go | 2 + .../github.com/minio/minio-go/v6/transport.go | 22 +- vendor/github.com/minio/minio-go/v6/utils.go | 5 + .../prometheus/alertmanager/api/v1/api.go | 10 +- .../prometheus/alertmanager/api/v2/api.go | 9 +- .../api/v2/restapi/configure_alertmanager.go | 72 +- .../operations/alert/get_alerts_responses.go | 6 +- .../operations/alert/get_alerts_urlbuilder.go | 40 +- .../operations/alert/post_alerts_responses.go | 2 - .../alertgroup/get_alert_groups_responses.go | 6 +- .../alertgroup/get_alert_groups_urlbuilder.go | 32 +- .../v2/restapi/operations/alertmanager_api.go | 6 +- .../receiver/get_receivers_responses.go | 2 +- .../silence/delete_silence_responses.go | 1 - .../silence/delete_silence_urlbuilder.go | 2 +- .../silence/get_silence_responses.go | 1 - .../silence/get_silence_urlbuilder.go | 2 +- .../silence/get_silences_responses.go | 5 +- .../silence/post_silences_responses.go | 2 - .../alertmanager/api/v2/restapi/server.go | 7 +- .../alertmanager/asset/assets_vfsdata.go | 4 +- .../alertmanager/cluster/cluster.go | 10 +- .../prometheus/alertmanager/config/config.go | 65 +- .../alertmanager/config/notifiers.go | 2 +- .../alertmanager/dispatch/dispatch.go | 52 +- .../alertmanager/inhibit/inhibit.go | 4 +- .../prometheus/alertmanager/nflog/nflog.go | 4 +- .../alertmanager/notify/email/email.go | 21 +- .../prometheus/alertmanager/notify/notify.go | 5 +- .../notify/pagerduty/pagerduty.go | 29 +- .../alertmanager/notify/wechat/wechat.go | 8 +- .../alertmanager/pkg/labels/matcher.go | 88 ++ .../pkg/{parse => labels}/parse.go | 56 +- .../alertmanager/provider/mem/mem.go | 4 +- .../alertmanager/silence/silence.go | 17 + .../prometheus/alertmanager/store/store.go | 35 +- .../alertmanager/template/template.go | 3 + .../prometheus/alertmanager/types/match.go | 23 +- .../prometheus/alertmanager/types/types.go | 5 +- .../thanos-io/thanos/pkg/block/block.go | 7 +- .../thanos-io/thanos/pkg/block/fetcher.go | 166 +++- .../thanos-io/thanos/pkg/block/index.go | 3 + .../pkg/block/indexheader/binary_reader.go | 828 ++++++++++++++++++ .../thanos/pkg/block/indexheader/header.go | 33 +- .../pkg/block/indexheader/json_reader.go | 57 +- .../thanos/pkg/block/metadata/meta.go | 3 + .../thanos-io/thanos/pkg/block/node.go | 53 ++ .../thanos/pkg/cacheutil/jump_hash.go | 3 + .../thanos/pkg/cacheutil/memcached_client.go | 3 + .../cacheutil/memcached_server_selector.go | 3 + .../thanos-io/thanos/pkg/compact/clean.go | 3 + .../thanos-io/thanos/pkg/compact/compact.go | 133 +-- .../thanos/pkg/compact/downsample/aggr.go | 3 + .../pkg/compact/downsample/downsample.go | 3 + .../thanos/pkg/compact/downsample/pool.go | 3 + .../downsample/streamed_block_writer.go | 6 +- .../thanos-io/thanos/pkg/compact/retention.go | 3 + .../thanos/pkg/component/component.go | 3 + .../pkg/discovery/dns/miekgdns/lookup.go | 3 + .../pkg/discovery/dns/miekgdns/resolver.go | 3 + .../thanos/pkg/discovery/dns/provider.go | 3 + .../thanos/pkg/discovery/dns/resolver.go | 3 + .../thanos-io/thanos/pkg/exthttp/transport.go | 3 + .../thanos-io/thanos/pkg/extprom/extprom.go | 3 + .../thanos-io/thanos/pkg/extprom/testing.go | 35 + .../thanos-io/thanos/pkg/extprom/tx_gauge.go | 3 + .../thanos-io/thanos/pkg/gate/gate.go | 8 + .../thanos/pkg/model/timeduration.go | 5 +- .../thanos/pkg/objstore/azure/azure.go | 3 + .../thanos/pkg/objstore/azure/helpers.go | 3 + .../thanos-io/thanos/pkg/objstore/gcs/gcs.go | 3 + .../thanos-io/thanos/pkg/objstore/objstore.go | 6 +- .../thanos-io/thanos/pkg/objstore/s3/s3.go | 3 + .../thanos-io/thanos/pkg/objstore/testing.go | 3 + .../thanos-io/thanos/pkg/pool/pool.go | 20 +- .../thanos-io/thanos/pkg/runutil/runutil.go | 3 + .../thanos-io/thanos/pkg/shipper/shipper.go | 9 +- .../thanos-io/thanos/pkg/store/bucket.go | 299 +++++-- .../thanos-io/thanos/pkg/store/cache/cache.go | 3 + .../thanos/pkg/store/cache/factory.go | 3 + .../thanos/pkg/store/cache/inmemory.go | 29 +- .../thanos/pkg/store/cache/memcached.go | 3 + .../thanos-io/thanos/pkg/store/cache/units.go | 3 + .../thanos-io/thanos/pkg/store/limiter.go | 7 + .../thanos-io/thanos/pkg/store/matchers.go | 3 + .../thanos-io/thanos/pkg/store/prometheus.go | 23 +- .../thanos-io/thanos/pkg/store/proxy.go | 158 ++-- .../thanos/pkg/store/storepb/custom.go | 3 + .../thanos/pkg/store/storepb/rpc.pb.go | 576 ++++++++++-- .../thanos/pkg/store/storepb/rpc.proto | 27 +- .../thanos/pkg/store/storepb/types.proto | 3 + .../thanos-io/thanos/pkg/store/tsdb.go | 9 + .../thanos-io/thanos/pkg/strutil/merge.go | 3 + .../thanos/pkg/testutil/testorbench.go | 75 ++ .../thanos-io/thanos/pkg/testutil/testutil.go | 98 +++ .../thanos-io/thanos/pkg/tracing/grpc.go | 3 + .../thanos-io/thanos/pkg/tracing/http.go | 3 + .../thanos-io/thanos/pkg/tracing/tracing.go | 3 + vendor/modules.txt | 13 +- 147 files changed, 4095 insertions(+), 946 deletions(-) create mode 100644 vendor/github.com/minio/minio-go/v6/api-get-bucket-encryption.go create mode 100644 vendor/github.com/minio/minio-go/v6/api-object-legal-hold.go create mode 100644 vendor/github.com/minio/minio-go/v6/api-object-tagging.go create mode 100644 vendor/github.com/prometheus/alertmanager/pkg/labels/matcher.go rename vendor/github.com/prometheus/alertmanager/pkg/{parse => labels}/parse.go (60%) create mode 100644 vendor/github.com/thanos-io/thanos/pkg/block/indexheader/binary_reader.go create mode 100644 vendor/github.com/thanos-io/thanos/pkg/block/node.go create mode 100644 vendor/github.com/thanos-io/thanos/pkg/extprom/testing.go create mode 100644 vendor/github.com/thanos-io/thanos/pkg/testutil/testorbench.go create mode 100644 vendor/github.com/thanos-io/thanos/pkg/testutil/testutil.go diff --git a/CHANGELOG.md b/CHANGELOG.md index ddd0f983b1a..df7f63f755d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ * [CHANGE] Experimental TSDB: the querier in-memory index cache used by the experimental blocks storage shifted from per-tenant to per-querier. The `-experimental.tsdb.bucket-store.index-cache-size-bytes` now configures the per-querier index cache max size instead of a per-tenant cache and its default has been increased to 1GB. #2189 * [CHANGE] If you are vendoring Cortex and use its components in your project, be aware that many Cortex components no longer start automatically when they are created. You may want to review PR and attached document. #2166 * [CHANGE] Cortex now has /ready probe for all services, not just ingester and querier as before. In single-binary mode, /ready reports 204 only if all components are running properly. #2166 +* [CHANGE] Experimental TSDB: switched the blocks storage index header to the binary format. This change is expected to have no visible impact, except lower startup times and memory usage in the queriers. It's possible to switch back to the old JSON format via the flag `-experimental.tsdb.bucket-store.binary-index-header-enabled=false`. * [FEATURE] Added a read-only local alertmanager config store using files named corresponding to their tenant id. #2125 * [FEATURE] Added user sub rings to distribute users to a subset of ingesters. #1947 * `--experimental.distributor.user-subring-size` diff --git a/docs/configuration/config-file-reference.md b/docs/configuration/config-file-reference.md index d392da129b4..469bd1cceb4 100644 --- a/docs/configuration/config-file-reference.md +++ b/docs/configuration/config-file-reference.md @@ -2198,6 +2198,17 @@ bucket_store: # CLI flag: -experimental.tsdb.bucket-store.meta-sync-concurrency [meta_sync_concurrency: | default = 20] + # Whether the bucket store should use the binary index header. If false, it + # uses the legacy JSON index header. + # CLI flag: -experimental.tsdb.bucket-store.binary-index-header-enabled + [binary_index_header_enabled: | default = true] + + # Minimum age of a block before it's being read. Set it to safe value (e.g + # 30m) if your object storage is eventually consistent. GCS and S3 are + # (roughly) strongly consistent. + # CLI flag: -experimental.tsdb.bucket-store.consistency-delay + [consistency_delay: | default = 0s] + # How frequently does Cortex try to compact TSDB head. Block is only created if # data covers smallest block range. Must be greater than 0 and max 5 minutes. # CLI flag: -experimental.tsdb.head-compaction-interval diff --git a/docs/operations/blocks-storage.md b/docs/operations/blocks-storage.md index 464126eb579..2a22c241b19 100644 --- a/docs/operations/blocks-storage.md +++ b/docs/operations/blocks-storage.md @@ -166,6 +166,17 @@ tsdb: # CLI flag: -experimental.tsdb.bucket-store.meta-sync-concurrency [meta_sync_concurrency: | default = 20] + # Whether the bucket store should use the binary index header. If false, it + # uses the legacy JSON index header. + # CLI flag: -experimental.tsdb.bucket-store.binary-index-header-enabled + [binary_index_header_enabled: | default = true] + + # Minimum age of a block before it's being read. Set it to safe value (e.g + # 30m) if your object storage is eventually consistent. GCS and S3 are + # (roughly) strongly consistent. + # CLI flag: -experimental.tsdb.bucket-store.consistency-delay + [consistency_delay: | default = 0s] + # How frequently does Cortex try to compact TSDB head. Block is only created # if data covers smallest block range. Must be greater than 0 and max 5 # minutes. diff --git a/go.mod b/go.mod index 0725cc69b42..cf4981a0fd3 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb github.com/fsouza/fake-gcs-server v1.7.0 github.com/go-kit/kit v0.9.0 + github.com/go-openapi/analysis v0.19.4 // indirect github.com/gocql/gocql v0.0.0-20200121121104-95d072f1b5bb github.com/gogo/protobuf v1.3.1 github.com/gogo/status v1.0.3 @@ -41,13 +42,14 @@ require ( github.com/lann/builder v0.0.0-20150808151131-f22ce00fd939 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.3.0 + github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect github.com/mitchellh/go-wordwrap v1.0.0 github.com/oklog/ulid v1.3.1 github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 github.com/opentracing/opentracing-go v1.1.1-0.20200124165624-2876d2018785 github.com/pkg/errors v0.8.1 - github.com/prometheus/alertmanager v0.19.0 + github.com/prometheus/alertmanager v0.20.0 github.com/prometheus/client_golang v1.5.0 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.9.1 @@ -56,7 +58,7 @@ require ( github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e github.com/spf13/afero v1.2.2 github.com/stretchr/testify v1.4.0 - github.com/thanos-io/thanos v0.8.1-0.20200109203923-552ffa4c1a0d + github.com/thanos-io/thanos v0.11.0 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect github.com/uber/jaeger-client-go v2.20.1+incompatible github.com/weaveworks/common v0.0.0-20200206153930-760e36ae819a @@ -68,6 +70,7 @@ require ( google.golang.org/api v0.14.0 google.golang.org/grpc v1.25.1 gopkg.in/yaml.v2 v2.2.7 + k8s.io/client-go v12.0.0+incompatible // indirect sigs.k8s.io/yaml v1.1.0 ) diff --git a/go.sum b/go.sum index 9b16d04b4c5..973648501f7 100644 --- a/go.sum +++ b/go.sum @@ -60,7 +60,6 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/squirrel v0.0.0-20161115235646-20f192218cf5 h1:PPfYWScYacO3Q6JMCLkyh6Ea2Q/REDTMgmiTAeiV8Jg= github.com/Masterminds/squirrel v0.0.0-20161115235646-20f192218cf5/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM= @@ -71,8 +70,6 @@ github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cq github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= -github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/OneOfOne/xxhash v1.2.6 h1:U68crOE3y3MPttCMQGywZOLrTeF5HHJ3/vDBCJn9/bA= github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -99,8 +96,6 @@ github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= github.com/armon/go-metrics v0.3.0 h1:B7AQgHi8QSEi4uHu7Sbsga+IJDU+CENgjxoo81vDUqU= github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -111,7 +106,6 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.22.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.48 h1:J82DYDGZHOKHdhx6hD24Tm30c2C3GchYGfN0mf9iKUk= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= @@ -270,8 +264,8 @@ github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.3 h1:pyVE0l7ybsThmn9Y9kWRK3o/cUmaT8WVfd6pDCIKeNE= -github.com/go-openapi/runtime v0.19.3/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/runtime v0.19.4 h1:csnOgcgAiuGoM/Po7PEpKDoNulCcF3FGbSnbHfxgjMI= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= 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= @@ -289,8 +283,8 @@ github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/ github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.4 h1:i/65mCM9s1h8eCkT07F5Z/C1e/f8VTgEwer+00yevpA= -github.com/go-openapi/swag v0.19.4/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 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 h1:ky5l57HjyVRrsJfd2+Ro5Z9PjGuKbsmftwyMtk8H7js= @@ -378,8 +372,6 @@ github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= -github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= @@ -457,8 +449,6 @@ github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/memberlist v0.1.5 h1:AYBsgJOW9gab/toO5tEB8lWetVgDKZycqkebJ8xxpqM= github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k= -github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hashicorp/serf v0.8.5 h1:ZynDUIQiA8usmRgPdGPHFdPnb1wgGI9tK3mO9hcAJjc= github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -478,8 +468,6 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 h1:K//n/AqR5HjG3qxbrBCL4vJPW0MVFSs9CPK1OOJdRME= -github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -559,8 +547,8 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.22 h1:Jm64b3bO9kP43ddLjL2EY3Io6bmy1qGb9Xxz6TqS6rc= github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/minio/minio-go/v6 v6.0.44 h1:CVwVXw+uCOcyMi7GvcOhxE8WgV+Xj8Vkf2jItDf/EGI= -github.com/minio/minio-go/v6 v6.0.44/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg= +github.com/minio/minio-go/v6 v6.0.49 h1:bU4kIa/qChTLC1jrWZ8F+8gOiw1MClubddAJVR4gW3w= +github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -649,15 +637,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE= -github.com/prometheus/alertmanager v0.19.0 h1:3EQZd4F0WKKeNiR01b+xP0bR+7ODas0BxyYuEC+guRM= -github.com/prometheus/alertmanager v0.19.0/go.mod h1:Eyp94Yi/T+kdeb2qvq66E3RGuph5T/jm/RBVh4yz1xo= +github.com/prometheus/alertmanager v0.20.0 h1:PBMNY7oyIvYMBBIag35/C0hO7xn8+35p4V5rNAph5N8= +github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg= 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= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.2.0/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= @@ -675,7 +661,6 @@ github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7q github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.8.0 h1:bLkjvFe2ZRX1DpcgZcdf7j/+MnusEps5hktST/FHA34= @@ -696,9 +681,7 @@ github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= -github.com/prometheus/prometheus v0.0.0-20190818123050-43acd0e2e93f/go.mod h1:rMTlmxGCvukf2KMu3fClMDKLLoJ5hl61MhcJ7xKakf0= -github.com/prometheus/prometheus v1.8.2-0.20200107122003-4708915ac6ef h1:pYYKXo/zGx25kyViw+Gdbxd0ItIg+vkVKpwgWUEyIc4= -github.com/prometheus/prometheus v1.8.2-0.20200107122003-4708915ac6ef/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI= +github.com/prometheus/prometheus v1.8.2-0.20200110114423-1e64d757f711/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI= github.com/prometheus/prometheus v1.8.2-0.20200213233353-b90be6f32a33 h1:HBYrMJj5iosUjUkAK9L5GO+5eEQXbcrzdjkqY9HV5W4= github.com/prometheus/prometheus v1.8.2-0.20200213233353-b90be6f32a33/go.mod h1:fkIPPkuZnkXyopYHmXPxf9rgiPkVgZCN8w9o8+UgBlY= github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1 h1:+kGqA4dNN5hn7WwvKdzHl0rdN5AEkbNZd0VjRltAiZg= @@ -769,8 +752,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/thanos-io/thanos v0.8.1-0.20200109203923-552ffa4c1a0d h1:kmHcmvQm1NUfBjJCf/j4ykZutUjHqUEdyfgMN8YmW38= -github.com/thanos-io/thanos v0.8.1-0.20200109203923-552ffa4c1a0d/go.mod h1:usT/TxtJQ7DzinTt+G9kinDQmRS5sxwu0unVKZ9vdcw= +github.com/thanos-io/thanos v0.11.0 h1:UkWLa93sihcxCofelRH/NBGQxFyFU73eXIr2a+dwOFM= +github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -805,7 +788,6 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20190709142735-eb7dd97135a5 h1:3unozPyUjPcbSbfhBb4EgA3O1/yBYHNgRr4ZGjO9iyQ= go.etcd.io/etcd v0.0.0-20190709142735-eb7dd97135a5/go.mod h1:N0RPWo9FXJYZQI4BTkDtQylrstIigYHeR18ONnyTufk= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.0.4/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.0 h1:aeOqSrhl9eDRAap/3T5pCfMBEBxZ0vuXBP+RMtp2KX8= go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -840,7 +822,6 @@ golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 h1:pXVtWnwHkrWD9ru3sDxY/qFK/bfc0egRovX91EjWjf4= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -936,7 +917,6 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1115,13 +1095,9 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= -k8s.io/kube-openapi v0.0.0-20190722073852-5e22f3d471e6 h1:s9IxTKe9GwDH0S/WaX62nFYr0or32DsTWex9AileL7U= -k8s.io/kube-openapi v0.0.0-20190722073852-5e22f3d471e6/go.mod h1:RZvgC8MSN6DjiMV6oIfEE9pDL9CYXokkfaCKZeHm3nc= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= -k8s.io/utils v0.0.0-20190809000727-6c36bc71fc4a h1:uy5HAgt4Ha5rEMbhZA+aM1j2cq5LmR6LQ71EYC2sVH4= -k8s.io/utils v0.0.0-20190809000727-6c36bc71fc4a/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6 h1:p0Ai3qVtkbCG/Af26dBmU0E1W58NID3hSSh7cMyylpM= k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= diff --git a/integration/querier_test.go b/integration/querier_test.go index 44eac2b7ab9..79a758838db 100644 --- a/integration/querier_test.go +++ b/integration/querier_test.go @@ -105,11 +105,6 @@ func TestQuerierWithBlocksStorage(t *testing.T) { require.NoError(t, querier.WaitSumMetrics(e2e.Equals(2), "cortex_querier_bucket_store_blocks_loaded")) // Query back the series (1 only in the storage, 1 only in the ingesters, 1 on both). - // TODO: apparently Thanos has a bug which cause a block to not be considered if the - // query timetamp matches the block max timestamp - series1Timestamp = series1Timestamp.Add(time.Duration(time.Millisecond)) - expectedVector1[0].Timestamp = model.Time(e2e.TimeToMilliseconds(series1Timestamp)) - result, err := c.Query("series_1", series1Timestamp) require.NoError(t, err) require.Equal(t, model.ValVector, result.Type()) @@ -208,11 +203,6 @@ func TestQuerierWithBlocksStorageOnMissingBlocksFromStorage(t *testing.T) { c, err = e2ecortex.NewClient("", querier.HTTPEndpoint(), "", "user-1") require.NoError(t, err) - // TODO: apparently Thanos has a bug which cause a block to not be considered if the - // query timetamp matches the block max timestamp - series1Timestamp = series1Timestamp.Add(time.Duration(time.Millisecond)) - expectedVector1[0].Timestamp = model.Time(e2e.TimeToMilliseconds(series1Timestamp)) - result, err := c.Query("series_1", series1Timestamp) require.NoError(t, err) require.Equal(t, model.ValVector, result.Type()) diff --git a/pkg/alertmanager/alertmanager.go b/pkg/alertmanager/alertmanager.go index 0d7cce998e4..43fb11bc572 100644 --- a/pkg/alertmanager/alertmanager.go +++ b/pkg/alertmanager/alertmanager.go @@ -72,7 +72,15 @@ type Alertmanager struct { active bool } -var webReload = make(chan chan error) +var ( + webReload = make(chan chan error) + + // Workaround a bug in the alertmanager which doesn't register the + // metrics in the input registry but to the global default one. + // TODO change once the vendored alertmanager will have this PR merged into: + // https://github.com/prometheus/alertmanager/pull/2200 + dispatcherMetrics = dispatch.NewDispatcherMetrics(prometheus.NewRegistry()) +) func init() { go func() { @@ -231,6 +239,7 @@ func (am *Alertmanager) ApplyConfig(userID string, conf *config.Config) error { am.marker, timeoutFunc, log.With(am.logger, "component", "dispatcher"), + dispatcherMetrics, ) go am.dispatcher.Run() diff --git a/pkg/compactor/compactor.go b/pkg/compactor/compactor.go index a4805bd9c72..594a749c1a9 100644 --- a/pkg/compactor/compactor.go +++ b/pkg/compactor/compactor.go @@ -301,6 +301,10 @@ func (c *Compactor) compactUser(ctx context.Context, userID string) error { ulogger := util.WithUserID(userID, c.logger) + // Filters out duplicate blocks that can be formed from two or more overlapping + // blocks that fully submatches the source blocks of the older blocks. + deduplicateBlocksFilter := block.NewDeduplicateFilter() + fetcher, err := block.NewMetaFetcher( ulogger, c.compactorCfg.MetaSyncConcurrency, @@ -310,7 +314,9 @@ func (c *Compactor) compactUser(ctx context.Context, userID string) error { // the directory used by the Thanos Syncer, whatever is the user ID. path.Join(c.compactorCfg.DataDir, "meta-"+userID), reg, - // No filters + // List of filters to apply (order matters). + block.NewConsistencyDelayMetaFilter(ulogger, c.compactorCfg.ConsistencyDelay, reg).Filter, + deduplicateBlocksFilter.Filter, ) if err != nil { return err @@ -321,6 +327,7 @@ func (c *Compactor) compactUser(ctx context.Context, userID string) error { reg, bucket, fetcher, + deduplicateBlocksFilter, c.compactorCfg.BlockSyncConcurrency, false, // Do not accept malformed indexes true, // Enable vertical compaction diff --git a/pkg/compactor/compactor_test.go b/pkg/compactor/compactor_test.go index 8d4c2a59311..0b863c5acf9 100644 --- a/pkg/compactor/compactor_test.go +++ b/pkg/compactor/compactor_test.go @@ -128,6 +128,10 @@ func TestCompactor_ShouldDoNothingOnNoUserBlocks(t *testing.T) { # TYPE cortex_compactor_garbage_collection_total counter cortex_compactor_garbage_collection_total 0 + # HELP cortex_compactor_meta_sync_consistency_delay_seconds TSDB Syncer: Configured consistency delay in seconds. + # TYPE cortex_compactor_meta_sync_consistency_delay_seconds gauge + cortex_compactor_meta_sync_consistency_delay_seconds 0 + # HELP cortex_compactor_meta_sync_duration_seconds TSDB Syncer: Duration of the blocks metadata synchronization in seconds. # TYPE cortex_compactor_meta_sync_duration_seconds histogram cortex_compactor_meta_sync_duration_seconds_bucket{le="+Inf"} 0 @@ -225,6 +229,10 @@ func TestCompactor_ShouldRetryOnFailureWhileDiscoveringUsersFromBucket(t *testin # TYPE cortex_compactor_garbage_collection_total counter cortex_compactor_garbage_collection_total 0 + # HELP cortex_compactor_meta_sync_consistency_delay_seconds TSDB Syncer: Configured consistency delay in seconds. + # TYPE cortex_compactor_meta_sync_consistency_delay_seconds gauge + cortex_compactor_meta_sync_consistency_delay_seconds 0 + # HELP cortex_compactor_meta_sync_duration_seconds TSDB Syncer: Duration of the blocks metadata synchronization in seconds. # TYPE cortex_compactor_meta_sync_duration_seconds histogram cortex_compactor_meta_sync_duration_seconds_bucket{le="+Inf"} 0 diff --git a/pkg/compactor/syncer_metrics.go b/pkg/compactor/syncer_metrics.go index 849e4bd0342..49ba8a5e4c8 100644 --- a/pkg/compactor/syncer_metrics.go +++ b/pkg/compactor/syncer_metrics.go @@ -13,6 +13,7 @@ type syncerMetrics struct { metaSync prometheus.Counter metaSyncFailures prometheus.Counter metaSyncDuration *util.HistogramDataCollector // was prometheus.Histogram before + metaSyncConsistencyDelay prometheus.Gauge garbageCollectedBlocks prometheus.Counter garbageCollections prometheus.Counter garbageCollectionFailures prometheus.Counter @@ -41,6 +42,10 @@ func newSyncerMetrics(reg prometheus.Registerer) *syncerMetrics { "cortex_compactor_meta_sync_duration_seconds", "TSDB Syncer: Duration of the blocks metadata synchronization in seconds.", nil, nil)) + m.metaSyncConsistencyDelay = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "cortex_compactor_meta_sync_consistency_delay_seconds", + Help: "TSDB Syncer: Configured consistency delay in seconds.", + }) m.garbageCollectedBlocks = prometheus.NewCounter(prometheus.CounterOpts{ Name: "cortex_compactor_garbage_collected_blocks_total", @@ -85,6 +90,7 @@ func newSyncerMetrics(reg prometheus.Registerer) *syncerMetrics { m.metaSync, m.metaSyncFailures, m.metaSyncDuration, + m.metaSyncConsistencyDelay, m.garbageCollectedBlocks, m.garbageCollections, m.garbageCollectionFailures, @@ -119,6 +125,7 @@ func (m *syncerMetrics) gatherThanosSyncerMetrics(reg *prometheus.Registry) { m.metaSync.Add(mfm.SumCounters("blocks_meta_syncs_total")) m.metaSyncFailures.Add(mfm.SumCounters("blocks_meta_sync_failures_total")) m.metaSyncDuration.Add(mfm.SumHistograms("blocks_meta_sync_duration_seconds")) + m.metaSyncConsistencyDelay.Set(mfm.MaxGauges("consistency_delay_seconds")) m.garbageCollectedBlocks.Add(mfm.SumCounters("thanos_compact_garbage_collected_blocks_total")) m.garbageCollections.Add(mfm.SumCounters("thanos_compact_garbage_collection_total")) diff --git a/pkg/compactor/syncer_metrics_test.go b/pkg/compactor/syncer_metrics_test.go index 889e09631a4..fea5854f425 100644 --- a/pkg/compactor/syncer_metrics_test.go +++ b/pkg/compactor/syncer_metrics_test.go @@ -19,6 +19,10 @@ func TestSyncerMetrics(t *testing.T) { // total base = 111110 err := testutil.GatherAndCompare(reg, bytes.NewBufferString(` + # HELP cortex_compactor_meta_sync_consistency_delay_seconds TSDB Syncer: Configured consistency delay in seconds. + # TYPE cortex_compactor_meta_sync_consistency_delay_seconds gauge + cortex_compactor_meta_sync_consistency_delay_seconds 300 + # HELP cortex_compactor_meta_syncs_total TSDB Syncer: Total blocks metadata synchronization attempts. # TYPE cortex_compactor_meta_syncs_total counter cortex_compactor_meta_syncs_total 111110 @@ -118,6 +122,7 @@ func generateTestData(base float64) *prometheus.Registry { m.metaSync.Add(1 * base) m.metaSyncFailures.Add(2 * base) m.metaSyncDuration.Observe(3 * base / 10000) + m.metaSyncConsistencyDelay.Set(300) m.garbageCollectedBlocks.Add(4 * base) m.garbageCollections.Add(5 * base) m.garbageCollectionFailures.Add(6 * base) @@ -145,6 +150,7 @@ type testSyncerMetrics struct { metaSync prometheus.Counter metaSyncFailures prometheus.Counter metaSyncDuration prometheus.Histogram + metaSyncConsistencyDelay prometheus.Gauge garbageCollectedBlocks prometheus.Counter garbageCollections prometheus.Counter garbageCollectionFailures prometheus.Counter @@ -172,6 +178,10 @@ func newTestSyncerMetrics(reg prometheus.Registerer) *testSyncerMetrics { Help: "Duration of the blocks metadata synchronization in seconds.", Buckets: []float64{0.01, 0.1, 0.3, 0.6, 1, 3, 6, 9, 20, 30, 60, 90, 120, 240, 360, 720}, }) + m.metaSyncConsistencyDelay = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "consistency_delay_seconds", + Help: "Configured consistency delay in seconds.", + }) m.garbageCollectedBlocks = prometheus.NewCounter(prometheus.CounterOpts{ Name: "thanos_compact_garbage_collected_blocks_total", @@ -217,6 +227,7 @@ func newTestSyncerMetrics(reg prometheus.Registerer) *testSyncerMetrics { m.metaSync, m.metaSyncFailures, m.metaSyncDuration, + m.metaSyncConsistencyDelay, m.garbageCollectedBlocks, m.garbageCollections, m.garbageCollectionFailures, diff --git a/pkg/ingester/metrics.go b/pkg/ingester/metrics.go index c67df6e7af3..573009109b1 100644 --- a/pkg/ingester/metrics.go +++ b/pkg/ingester/metrics.go @@ -143,7 +143,7 @@ func newTSDBMetrics(r prometheus.Registerer) *tsdbMetrics { dirSyncs: prometheus.NewDesc( "cortex_ingester_shipper_dir_syncs_total", - "TSDB: Total dir sync attempts", + "TSDB: Total number of dir syncs", nil, nil), dirSyncFailures: prometheus.NewDesc( "cortex_ingester_shipper_dir_sync_failures_total", @@ -151,11 +151,11 @@ func newTSDBMetrics(r prometheus.Registerer) *tsdbMetrics { nil, nil), uploads: prometheus.NewDesc( "cortex_ingester_shipper_uploads_total", - "TSDB: Total object upload attempts", + "TSDB: Total number of uploaded blocks", nil, nil), uploadFailures: prometheus.NewDesc( "cortex_ingester_shipper_upload_failures_total", - "TSDB: Total number of failed object uploads", + "TSDB: Total number of block upload failures", nil, nil), memSeriesCreatedTotal: prometheus.NewDesc(memSeriesCreatedTotalName, memSeriesCreatedTotalHelp, []string{"user"}, nil), diff --git a/pkg/ingester/metrics_test.go b/pkg/ingester/metrics_test.go index 749cbe4ca48..a9dfacb048d 100644 --- a/pkg/ingester/metrics_test.go +++ b/pkg/ingester/metrics_test.go @@ -19,7 +19,7 @@ func TestTSDBMetrics(t *testing.T) { tsdbMetrics.setRegistryForUser("user3", populateTSDBMetrics(999)) err := testutil.GatherAndCompare(mainReg, bytes.NewBufferString(` - # HELP cortex_ingester_shipper_dir_syncs_total TSDB: Total dir sync attempts + # HELP cortex_ingester_shipper_dir_syncs_total TSDB: Total number of dir syncs # TYPE cortex_ingester_shipper_dir_syncs_total counter # 12345 + 85787 + 999 cortex_ingester_shipper_dir_syncs_total 99131 @@ -29,12 +29,12 @@ func TestTSDBMetrics(t *testing.T) { # 2*(12345 + 85787 + 999) cortex_ingester_shipper_dir_sync_failures_total 198262 - # HELP cortex_ingester_shipper_uploads_total TSDB: Total object upload attempts + # HELP cortex_ingester_shipper_uploads_total TSDB: Total number of uploaded blocks # TYPE cortex_ingester_shipper_uploads_total counter # 3*(12345 + 85787 + 999) cortex_ingester_shipper_uploads_total 297393 - # HELP cortex_ingester_shipper_upload_failures_total TSDB: Total number of failed object uploads + # HELP cortex_ingester_shipper_upload_failures_total TSDB: Total number of block upload failures # TYPE cortex_ingester_shipper_upload_failures_total counter # 4*(12345 + 85787 + 999) cortex_ingester_shipper_upload_failures_total 396524 @@ -62,7 +62,7 @@ func populateTSDBMetrics(base float64) *prometheus.Registry { // shipper dirSyncs := prometheus.NewCounter(prometheus.CounterOpts{ Name: "thanos_shipper_dir_syncs_total", - Help: "Total dir sync attempts", + Help: "Total number of dir syncs", }) dirSyncs.Add(1 * base) @@ -74,13 +74,13 @@ func populateTSDBMetrics(base float64) *prometheus.Registry { uploads := prometheus.NewCounter(prometheus.CounterOpts{ Name: "thanos_shipper_uploads_total", - Help: "Total object upload attempts", + Help: "Total number of uploaded blocks", }) uploads.Add(3 * base) uploadFailures := prometheus.NewCounter(prometheus.CounterOpts{ Name: "thanos_shipper_upload_failures_total", - Help: "Total number of failed object uploads", + Help: "Total number of block upload failures", }) uploadFailures.Add(4 * base) diff --git a/pkg/querier/block_store.go b/pkg/querier/block_store.go index 1da55340987..621674a46d4 100644 --- a/pkg/querier/block_store.go +++ b/pkg/querier/block_store.go @@ -16,7 +16,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/thanos-io/thanos/pkg/block" - "github.com/thanos-io/thanos/pkg/model" "github.com/thanos-io/thanos/pkg/objstore" "github.com/thanos-io/thanos/pkg/runutil" "github.com/thanos-io/thanos/pkg/store" @@ -44,9 +43,6 @@ type UserStore struct { bucketStoreMetrics *tsdbBucketStoreMetrics indexCacheMetrics *tsdbIndexCacheMetrics - syncMint model.TimeOrDurationValue - syncMaxt model.TimeOrDurationValue - // Index cache shared across all tenants. indexCache storecache.IndexCache @@ -79,16 +75,8 @@ func NewUserStore(cfg tsdb.Config, bucketClient objstore.Bucket, logLevel loggin }), } - // Configure the time range to sync all blocks. - var err error - if err = u.syncMint.Set("0000-01-01T00:00:00Z"); err != nil { - return nil, err - } - if err = u.syncMaxt.Set("9999-12-31T23:59:59Z"); err != nil { - return nil, err - } - // Init the index cache. + var err error if u.indexCache, err = tsdb.NewIndexCache(cfg.BucketStore, logger, indexCacheRegistry); err != nil { return nil, errors.Wrap(err, "create index cache") } @@ -382,7 +370,11 @@ func (u *UserStore) getOrCreateStore(userID string) (*store.BucketStore, error) userBkt, filepath.Join(u.cfg.BucketStore.SyncDir, userID), // The fetcher stores cached metas in the "meta-syncer/" sub directory reg, - // No filters + // List of filters to apply (order matters). + block.NewConsistencyDelayMetaFilter(userLogger, u.cfg.BucketStore.ConsistencyDelay, reg).Filter, + // Filters out duplicate blocks that can be formed from two or more overlapping + // blocks that fully submatches the source blocks of the older blocks. + block.NewDeduplicateFilter().Filter, ) if err != nil { return nil, err @@ -400,11 +392,9 @@ func (u *UserStore) getOrCreateStore(userID string) (*store.BucketStore, error) u.cfg.BucketStore.MaxConcurrent, u.logLevel.String() == "debug", // Turn on debug logging, if the log level is set to debug u.cfg.BucketStore.BlockSyncConcurrency, - &store.FilterConfig{ - MinTime: u.syncMint, - MaxTime: u.syncMaxt, - }, + nil, // Do not limit timerange. false, // No need to enable backward compatibility with Thanos pre 0.8.0 queriers + u.cfg.BucketStore.BinaryIndexHeader, ) if err != nil { return nil, err diff --git a/pkg/querier/block_store_metrics.go b/pkg/querier/block_store_metrics.go index 91d38116440..bdaae2958de 100644 --- a/pkg/querier/block_store_metrics.go +++ b/pkg/querier/block_store_metrics.go @@ -16,22 +16,24 @@ type tsdbBucketStoreMetrics struct { regs map[string]*prometheus.Registry // exported metrics, gathered from Thanos BucketStore - blockLoads *prometheus.Desc - blockLoadFailures *prometheus.Desc - blockDrops *prometheus.Desc - blockDropFailures *prometheus.Desc - blocksLoaded *prometheus.Desc - seriesDataTouched *prometheus.Desc - seriesDataFetched *prometheus.Desc - seriesDataSizeTouched *prometheus.Desc - seriesDataSizeFetched *prometheus.Desc - seriesBlocksQueried *prometheus.Desc - seriesGetAllDuration *prometheus.Desc - seriesMergeDuration *prometheus.Desc - resultSeriesCount *prometheus.Desc - metaSyncs *prometheus.Desc - metaSyncFailures *prometheus.Desc - metaSyncDuration *prometheus.Desc + blockLoads *prometheus.Desc + blockLoadFailures *prometheus.Desc + blockDrops *prometheus.Desc + blockDropFailures *prometheus.Desc + blocksLoaded *prometheus.Desc + seriesDataTouched *prometheus.Desc + seriesDataFetched *prometheus.Desc + seriesDataSizeTouched *prometheus.Desc + seriesDataSizeFetched *prometheus.Desc + seriesBlocksQueried *prometheus.Desc + seriesGetAllDuration *prometheus.Desc + seriesMergeDuration *prometheus.Desc + seriesRefetches *prometheus.Desc + resultSeriesCount *prometheus.Desc + metaSyncs *prometheus.Desc + metaSyncFailures *prometheus.Desc + metaSyncDuration *prometheus.Desc + metaSyncConsistencyDelay *prometheus.Desc // Ignored: // blocks_meta_synced @@ -90,6 +92,10 @@ func newTSDBBucketStoreMetrics() *tsdbBucketStoreMetrics { "cortex_querier_bucket_store_series_merge_duration_seconds", "TSDB: Time it takes to merge sub-results from all queried blocks into a single result.", nil, nil), + seriesRefetches: prometheus.NewDesc( + "cortex_querier_bucket_store_series_refetches_total", + "TSDB: Total number of cases where the built-in max series size was not enough to fetch series from index, resulting in refetch.", + nil, nil), resultSeriesCount: prometheus.NewDesc( "cortex_querier_bucket_store_series_result_series", "TSDB: Number of series observed in the final result of a query.", @@ -106,6 +112,10 @@ func newTSDBBucketStoreMetrics() *tsdbBucketStoreMetrics { "cortex_querier_bucket_store_blocks_meta_sync_duration_seconds", "TSDB: Duration of the blocks metadata synchronization in seconds", nil, nil), + metaSyncConsistencyDelay: prometheus.NewDesc( + "cortex_querier_bucket_store_blocks_meta_sync_consistency_delay_seconds", + "TSDB: Configured consistency delay in seconds.", + nil, nil), } } @@ -140,11 +150,13 @@ func (m *tsdbBucketStoreMetrics) Describe(out chan<- *prometheus.Desc) { out <- m.seriesBlocksQueried out <- m.seriesGetAllDuration out <- m.seriesMergeDuration + out <- m.seriesRefetches out <- m.resultSeriesCount out <- m.metaSyncs out <- m.metaSyncFailures out <- m.metaSyncDuration + out <- m.metaSyncConsistencyDelay } func (m *tsdbBucketStoreMetrics) Collect(out chan<- prometheus.Metric) { @@ -165,11 +177,13 @@ func (m *tsdbBucketStoreMetrics) Collect(out chan<- prometheus.Metric) { data.SendSumOfHistograms(out, m.seriesGetAllDuration, "thanos_bucket_store_series_get_all_duration_seconds") data.SendSumOfHistograms(out, m.seriesMergeDuration, "thanos_bucket_store_series_merge_duration_seconds") + data.SendSumOfCounters(out, m.seriesRefetches, "thanos_bucket_store_series_refetches_total") data.SendSumOfSummaries(out, m.resultSeriesCount, "thanos_bucket_store_series_result_series") data.SendSumOfCounters(out, m.metaSyncs, "blocks_meta_syncs_total") data.SendSumOfCounters(out, m.metaSyncFailures, "blocks_meta_sync_failures_total") data.SendSumOfHistograms(out, m.metaSyncDuration, "blocks_meta_sync_duration_seconds") + data.SendMaxOfGauges(out, m.metaSyncConsistencyDelay, "consistency_delay_seconds") } // This struct aggregates metrics exported by Thanos Index Cache diff --git a/pkg/querier/bucket_store_metrics_test.go b/pkg/querier/bucket_store_metrics_test.go index 5bf530af274..adc3d78a1e5 100644 --- a/pkg/querier/bucket_store_metrics_test.go +++ b/pkg/querier/bucket_store_metrics_test.go @@ -137,10 +137,18 @@ func TestTSDBBucketStoreMetrics(t *testing.T) { # TYPE cortex_querier_bucket_store_blocks_meta_syncs_total counter cortex_querier_bucket_store_blocks_meta_syncs_total 0 + # HELP cortex_querier_bucket_store_series_refetches_total TSDB: Total number of cases where the built-in max series size was not enough to fetch series from index, resulting in refetch. + # TYPE cortex_querier_bucket_store_series_refetches_total counter + cortex_querier_bucket_store_series_refetches_total 743127 + # HELP cortex_querier_bucket_store_series_result_series TSDB: Number of series observed in the final result of a query. # TYPE cortex_querier_bucket_store_series_result_series summary cortex_querier_bucket_store_series_result_series_sum 1.238545e+06 cortex_querier_bucket_store_series_result_series_count 6 + + # HELP cortex_querier_bucket_store_blocks_meta_sync_consistency_delay_seconds TSDB: Configured consistency delay in seconds. + # TYPE cortex_querier_bucket_store_blocks_meta_sync_consistency_delay_seconds gauge + cortex_querier_bucket_store_blocks_meta_sync_consistency_delay_seconds 300 `)) require.NoError(t, err) } @@ -191,7 +199,6 @@ func TestTSDBIndexCacheMetrics(t *testing.T) { # TYPE cortex_querier_blocks_index_cache_items_overflowed_total counter cortex_querier_blocks_index_cache_items_overflowed_total{item_type="Postings"} 79920 cortex_querier_blocks_index_cache_items_overflowed_total{item_type="Series"} 85248 - `)) require.NoError(t, err) } @@ -275,6 +282,10 @@ func populateTSDBBucketStoreMetrics(base float64) *prometheus.Registry { m.queriesDropped.Add(31 * base) m.queriesLimit.Add(32 * base) + m.seriesRefetches.Add(33 * base) + + m.metaSyncConsistencyDelay.Set(300) + return reg } @@ -304,22 +315,24 @@ func populateTSDBIndexCacheMetrics(base float64) *prometheus.Registry { // copied from Thanos, pkg/store/bucket.go type bucketStoreMetrics struct { - blocksLoaded prometheus.Gauge - blockLoads prometheus.Counter - blockLoadFailures prometheus.Counter - blockDrops prometheus.Counter - blockDropFailures prometheus.Counter - seriesDataTouched *prometheus.SummaryVec - seriesDataFetched *prometheus.SummaryVec - seriesDataSizeTouched *prometheus.SummaryVec - seriesDataSizeFetched *prometheus.SummaryVec - seriesBlocksQueried prometheus.Summary - seriesGetAllDuration prometheus.Histogram - seriesMergeDuration prometheus.Histogram - resultSeriesCount prometheus.Summary - chunkSizeBytes prometheus.Histogram - queriesDropped prometheus.Counter - queriesLimit prometheus.Gauge + blocksLoaded prometheus.Gauge + blockLoads prometheus.Counter + blockLoadFailures prometheus.Counter + blockDrops prometheus.Counter + blockDropFailures prometheus.Counter + seriesDataTouched *prometheus.SummaryVec + seriesDataFetched *prometheus.SummaryVec + seriesDataSizeTouched *prometheus.SummaryVec + seriesDataSizeFetched *prometheus.SummaryVec + seriesBlocksQueried prometheus.Summary + seriesGetAllDuration prometheus.Histogram + seriesMergeDuration prometheus.Histogram + seriesRefetches prometheus.Counter + resultSeriesCount prometheus.Summary + chunkSizeBytes prometheus.Histogram + queriesDropped prometheus.Counter + queriesLimit prometheus.Gauge + metaSyncConsistencyDelay prometheus.Gauge } // Copied from Thanos, pkg/store/cache/inmemory.go, InMemoryIndexCache struct @@ -395,6 +408,10 @@ func newBucketStoreMetrics(reg prometheus.Registerer) *bucketStoreMetrics { Help: "Time it takes to merge sub-results from all queried blocks into a single result.", Buckets: []float64{0.001, 0.01, 0.1, 0.3, 0.6, 1, 3, 6, 9, 20, 30, 60, 90, 120}, }) + m.seriesRefetches = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "thanos_bucket_store_series_refetches_total", + Help: "Total number of cases where the built-in max series size was not enough to fetch series from index, resulting in refetch.", + }) m.resultSeriesCount = prometheus.NewSummary(prometheus.SummaryOpts{ Name: "thanos_bucket_store_series_result_series", Help: "Number of series observed in the final result of a query.", @@ -417,6 +434,11 @@ func newBucketStoreMetrics(reg prometheus.Registerer) *bucketStoreMetrics { Help: "Number of maximum concurrent queries.", }) + m.metaSyncConsistencyDelay = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "consistency_delay_seconds", + Help: "Configured consistency delay in seconds.", + }) + if reg != nil { reg.MustRegister( m.blockLoads, @@ -431,10 +453,12 @@ func newBucketStoreMetrics(reg prometheus.Registerer) *bucketStoreMetrics { m.seriesBlocksQueried, m.seriesGetAllDuration, m.seriesMergeDuration, + m.seriesRefetches, m.resultSeriesCount, m.chunkSizeBytes, m.queriesDropped, m.queriesLimit, + m.metaSyncConsistencyDelay, ) } return &m diff --git a/pkg/storage/tsdb/config.go b/pkg/storage/tsdb/config.go index 20822a2f8fe..4b871109bde 100644 --- a/pkg/storage/tsdb/config.go +++ b/pkg/storage/tsdb/config.go @@ -155,6 +155,8 @@ type BucketStoreConfig struct { TenantSyncConcurrency int `yaml:"tenant_sync_concurrency"` BlockSyncConcurrency int `yaml:"block_sync_concurrency"` MetaSyncConcurrency int `yaml:"meta_sync_concurrency"` + BinaryIndexHeader bool `yaml:"binary_index_header_enabled"` + ConsistencyDelay time.Duration `yaml:"consistency_delay"` } // RegisterFlags registers the BucketStore flags @@ -168,6 +170,8 @@ func (cfg *BucketStoreConfig) RegisterFlags(f *flag.FlagSet) { f.IntVar(&cfg.TenantSyncConcurrency, "experimental.tsdb.bucket-store.tenant-sync-concurrency", 10, "Maximum number of concurrent tenants synching blocks.") f.IntVar(&cfg.BlockSyncConcurrency, "experimental.tsdb.bucket-store.block-sync-concurrency", 20, "Maximum number of concurrent blocks synching per tenant.") f.IntVar(&cfg.MetaSyncConcurrency, "experimental.tsdb.bucket-store.meta-sync-concurrency", 20, "Number of Go routines to use when syncing block meta files from object storage per tenant.") + f.BoolVar(&cfg.BinaryIndexHeader, "experimental.tsdb.bucket-store.binary-index-header-enabled", true, "Whether the bucket store should use the binary index header. If false, it uses the legacy JSON index header.") + f.DurationVar(&cfg.ConsistencyDelay, "experimental.tsdb.bucket-store.consistency-delay", 0, "Minimum age of a block before it's being read. Set it to safe value (e.g 30m) if your object storage is eventually consistent. GCS and S3 are (roughly) strongly consistent.") } // BlocksDir returns the directory path where TSDB blocks and wal should be diff --git a/pkg/util/metrics_helper.go b/pkg/util/metrics_helper.go index 47cc0d30f2d..b4aeabb48b2 100644 --- a/pkg/util/metrics_helper.go +++ b/pkg/util/metrics_helper.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "math" "sync" "github.com/go-kit/kit/log/level" @@ -78,6 +79,10 @@ func (mfm MetricFamilyMap) SumGauges(name string) float64 { return sum(mfm[name], gaugeValue) } +func (mfm MetricFamilyMap) MaxGauges(name string) float64 { + return max(mfm[name], gaugeValue) +} + func (mfm MetricFamilyMap) SumHistograms(name string) HistogramData { hd := HistogramData{} mfm.SumHistogramsTo(name, &hd) @@ -188,6 +193,22 @@ func (d MetricFamiliesPerUser) sumOfSingleValuesWithLabels(metric string, fn fun return result } +func (d MetricFamiliesPerUser) SendMaxOfGauges(out chan<- prometheus.Metric, desc *prometheus.Desc, gauge string) { + result := math.NaN() + for _, userMetrics := range d { + if value := userMetrics.MaxGauges(gauge); math.IsNaN(result) || value > result { + result = value + } + } + + // If there's no metric, we do send 0 which is the gauge default. + if math.IsNaN(result) { + result = 0 + } + + out <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, result) +} + func (d MetricFamiliesPerUser) SendSumOfSummaries(out chan<- prometheus.Metric, desc *prometheus.Desc, summaryName string) { summaryData := SummaryData{} for _, userMetrics := range d { @@ -296,6 +317,25 @@ func sum(mf *dto.MetricFamily, fn func(*dto.Metric) float64) float64 { return result } +// max returns the max value from all metrics from same metric family (= series with the same metric name, but different labels) +// Supplied function extracts value. +func max(mf *dto.MetricFamily, fn func(*dto.Metric) float64) float64 { + result := math.NaN() + + for _, m := range mf.GetMetric() { + if value := fn(m); math.IsNaN(result) || value > result { + result = value + } + } + + // If there's no metric, we do return 0 which is the gauge default. + if math.IsNaN(result) { + return 0 + } + + return result +} + // This works even if m is nil, m.Counter is nil or m.Counter.Value is nil (it returns 0 in those cases) func counterValue(m *dto.Metric) float64 { return m.GetCounter().GetValue() } func gaugeValue(m *dto.Metric) float64 { return m.GetGauge().GetValue() } diff --git a/pkg/util/metrics_helper_test.go b/pkg/util/metrics_helper_test.go index aec2a348bbe..1bf41493e80 100644 --- a/pkg/util/metrics_helper_test.go +++ b/pkg/util/metrics_helper_test.go @@ -5,6 +5,7 @@ import ( "github.com/gogo/protobuf/proto" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" dto "github.com/prometheus/client_model/go" "github.com/stretchr/testify/require" ) @@ -25,6 +26,22 @@ func TestSum(t *testing.T) { }}, counterValue)) } +func TestMax(t *testing.T) { + require.Equal(t, float64(0), max(nil, counterValue)) + require.Equal(t, float64(0), max(&dto.MetricFamily{Metric: nil}, counterValue)) + require.Equal(t, float64(0), max(&dto.MetricFamily{Metric: []*dto.Metric{{Counter: &dto.Counter{}}}}, counterValue)) + require.Equal(t, 12345.6789, max(&dto.MetricFamily{Metric: []*dto.Metric{{Counter: &dto.Counter{Value: proto.Float64(12345.6789)}}}}, counterValue)) + require.Equal(t, 7890.12345, max(&dto.MetricFamily{Metric: []*dto.Metric{ + {Counter: &dto.Counter{Value: proto.Float64(1234.56789)}}, + {Counter: &dto.Counter{Value: proto.Float64(7890.12345)}}, + }}, counterValue)) + // using 'counterValue' as function only works on counters + require.Equal(t, float64(0), max(&dto.MetricFamily{Metric: []*dto.Metric{ + {Gauge: &dto.Gauge{Value: proto.Float64(12345.6789)}}, + {Gauge: &dto.Gauge{Value: proto.Float64(7890.12345)}}, + }}, counterValue)) +} + func TestCounterValue(t *testing.T) { require.Equal(t, float64(0), counterValue(nil)) require.Equal(t, float64(0), counterValue(&dto.Metric{})) @@ -141,6 +158,45 @@ func TestSendSumOfGaugesPerUserWithLabels(t *testing.T) { require.ElementsMatch(t, expected, actual) } +func TestSendMaxOfGauges(t *testing.T) { + user1Reg := prometheus.NewRegistry() + user2Reg := prometheus.NewRegistry() + desc := prometheus.NewDesc("test_metric", "", nil, nil) + + // No matching metric. + mf := BuildMetricFamiliesPerUserFromUserRegistries(map[string]*prometheus.Registry{ + "user-1": user1Reg, + "user-2": user2Reg, + }) + actual, err := collectMetrics(func(out chan prometheus.Metric) { + mf.SendMaxOfGauges(out, desc, "test_metric") + }) + expected := []*dto.Metric{ + {Label: nil, Gauge: &dto.Gauge{Value: proto.Float64(0)}}, + } + require.NoError(t, err) + require.ElementsMatch(t, expected, actual) + + // Register a metric for each user. + user1Metric := promauto.With(user1Reg).NewGauge(prometheus.GaugeOpts{Name: "test_metric"}) + user2Metric := promauto.With(user2Reg).NewGauge(prometheus.GaugeOpts{Name: "test_metric"}) + user1Metric.Set(100) + user2Metric.Set(80) + mf = BuildMetricFamiliesPerUserFromUserRegistries(map[string]*prometheus.Registry{ + "user-1": user1Reg, + "user-2": user2Reg, + }) + + actual, err = collectMetrics(func(out chan prometheus.Metric) { + mf.SendMaxOfGauges(out, desc, "test_metric") + }) + expected = []*dto.Metric{ + {Label: nil, Gauge: &dto.Gauge{Value: proto.Float64(100)}}, + } + require.NoError(t, err) + require.ElementsMatch(t, expected, actual) +} + func collectMetrics(send func(out chan prometheus.Metric)) ([]*dto.Metric, error) { out := make(chan prometheus.Metric) diff --git a/vendor/github.com/go-openapi/runtime/request.go b/vendor/github.com/go-openapi/runtime/request.go index 87b73da45c2..9e51b42b59d 100644 --- a/vendor/github.com/go-openapi/runtime/request.go +++ b/vendor/github.com/go-openapi/runtime/request.go @@ -15,6 +15,7 @@ package runtime import ( + "bufio" "io" "net/http" "strings" @@ -42,7 +43,68 @@ func AllowsBody(r *http.Request) bool { // HasBody returns true if this method needs a content-type func HasBody(r *http.Request) bool { - return len(r.TransferEncoding) > 0 || r.ContentLength > 0 + // happy case: we have a content length set + if r.ContentLength > 0 { + return true + } + + if r.Header.Get(http.CanonicalHeaderKey("content-length")) != "" { + // in this case, no Transfer-Encoding should be present + // we have a header set but it was explicitly set to 0, so we assume no body + return false + } + + rdr := newPeekingReader(r.Body) + r.Body = rdr + return rdr.HasContent() +} + +func newPeekingReader(r io.ReadCloser) *peekingReader { + if r == nil { + return nil + } + return &peekingReader{ + underlying: bufio.NewReader(r), + orig: r, + } +} + +type peekingReader struct { + underlying interface { + Buffered() int + Peek(int) ([]byte, error) + Read([]byte) (int, error) + } + orig io.ReadCloser +} + +func (p *peekingReader) HasContent() bool { + if p == nil { + return false + } + if p.underlying.Buffered() > 0 { + return true + } + b, err := p.underlying.Peek(1) + if err != nil { + return false + } + return len(b) > 0 +} + +func (p *peekingReader) Read(d []byte) (int, error) { + if p == nil { + return 0, io.EOF + } + return p.underlying.Read(d) +} + +func (p *peekingReader) Close() error { + p.underlying = nil + if p.orig != nil { + return p.orig.Close() + } + return nil } // JSONRequest creates a new http request with json headers set diff --git a/vendor/github.com/go-openapi/runtime/security/authenticator.go b/vendor/github.com/go-openapi/runtime/security/authenticator.go index 21be9a1b99c..5d058b8d1fb 100644 --- a/vendor/github.com/go-openapi/runtime/security/authenticator.go +++ b/vendor/github.com/go-openapi/runtime/security/authenticator.go @@ -75,6 +75,7 @@ type secCtxKey uint8 const ( failedBasicAuth secCtxKey = iota + oauth2SchemeName ) func FailedBasicAuth(r *http.Request) string { @@ -89,6 +90,18 @@ func FailedBasicAuthCtx(ctx context.Context) string { return v } +func OAuth2SchemeName(r *http.Request) string { + return OAuth2SchemeNameCtx(r.Context()) +} + +func OAuth2SchemeNameCtx(ctx context.Context) string { + v, ok := ctx.Value(oauth2SchemeName).(string) + if !ok { + return "" + } + return v +} + // BasicAuth creates a basic auth authenticator with the provided authentication function func BasicAuth(authenticate UserPassAuthentication) runtime.Authenticator { return BasicAuthRealm(DefaultRealmName, authenticate) @@ -224,6 +237,8 @@ func BearerAuth(name string, authenticate ScopedTokenAuthentication) runtime.Aut return false, nil, nil } + rctx := context.WithValue(r.Request.Context(), oauth2SchemeName, name) + *r.Request = *r.Request.WithContext(rctx) p, err := authenticate(token, r.RequiredScopes) return true, p, err }) @@ -252,7 +267,8 @@ func BearerAuthCtx(name string, authenticate ScopedTokenAuthenticationCtx) runti return false, nil, nil } - ctx, p, err := authenticate(r.Request.Context(), token, r.RequiredScopes) + rctx := context.WithValue(r.Request.Context(), oauth2SchemeName, name) + ctx, p, err := authenticate(rctx, token, r.RequiredScopes) *r.Request = *r.Request.WithContext(ctx) return true, p, err }) diff --git a/vendor/github.com/go-openapi/swag/yaml.go b/vendor/github.com/go-openapi/swag/yaml.go index 435e2948eb6..ec96914405b 100644 --- a/vendor/github.com/go-openapi/swag/yaml.go +++ b/vendor/github.com/go-openapi/swag/yaml.go @@ -143,19 +143,43 @@ func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) { } func transformData(input interface{}) (out interface{}, err error) { + format := func(t interface{}) (string, error) { + switch k := t.(type) { + case string: + return k, nil + case uint: + return strconv.FormatUint(uint64(k), 10), nil + case uint8: + return strconv.FormatUint(uint64(k), 10), nil + case uint16: + return strconv.FormatUint(uint64(k), 10), nil + case uint32: + return strconv.FormatUint(uint64(k), 10), nil + case uint64: + return strconv.FormatUint(k, 10), nil + case int: + return strconv.Itoa(k), nil + case int8: + return strconv.FormatInt(int64(k), 10), nil + case int16: + return strconv.FormatInt(int64(k), 10), nil + case int32: + return strconv.FormatInt(int64(k), 10), nil + case int64: + return strconv.FormatInt(k, 10), nil + default: + return "", fmt.Errorf("unexpected map key type, got: %T", k) + } + } + switch in := input.(type) { case yaml.MapSlice: o := make(JSONMapSlice, len(in)) for i, mi := range in { var nmi JSONMapItem - switch k := mi.Key.(type) { - case string: - nmi.Key = k - case int: - nmi.Key = strconv.Itoa(k) - default: - return nil, fmt.Errorf("types don't match expect map key string or int got: %T", mi.Key) + if nmi.Key, err = format(mi.Key); err != nil { + return nil, err } v, ert := transformData(mi.Value) @@ -170,13 +194,8 @@ func transformData(input interface{}) (out interface{}, err error) { o := make(JSONMapSlice, 0, len(in)) for ke, va := range in { var nmi JSONMapItem - switch k := ke.(type) { - case string: - nmi.Key = k - case int: - nmi.Key = strconv.Itoa(k) - default: - return nil, fmt.Errorf("types don't match expect map key string or int got: %T", ke) + if nmi.Key, err = format(ke); err != nil { + return nil, err } v, ert := transformData(va) diff --git a/vendor/github.com/minio/minio-go/v6/README.md b/vendor/github.com/minio/minio-go/v6/README.md index 810a93941c7..33eb6c44dec 100644 --- a/vendor/github.com/minio/minio-go/v6/README.md +++ b/vendor/github.com/minio/minio-go/v6/README.md @@ -190,6 +190,11 @@ The full API Reference is available here. * [setbucketlifecycle.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketlifecycle.go) * [getbucketlifecycle.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketlifecycle.go) +### Full Examples : Bucket encryption Operations +* [setbucketencryption.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketencryption.go) +* [getbucketencryption.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketencryption.go) +* [deletebucketencryption.go](https://github.com/minio/minio-go/blob/master/examples/s3/deletebucketencryption.go) + ### Full Examples : Bucket notification Operations * [setbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketnotification.go) * [getbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketnotification.go) diff --git a/vendor/github.com/minio/minio-go/v6/api-compose-object.go b/vendor/github.com/minio/minio-go/v6/api-compose-object.go index 748b558ce3e..c9e44c556e4 100644 --- a/vendor/github.com/minio/minio-go/v6/api-compose-object.go +++ b/vendor/github.com/minio/minio-go/v6/api-compose-object.go @@ -36,18 +36,53 @@ import ( // created via server-side copy requests, using the Compose API. type DestinationInfo struct { bucket, object string - encryption encrypt.ServerSide + opts DestInfoOptions +} +// DestInfoOptions represents options specified by user for NewDestinationInfo call +type DestInfoOptions struct { + // `Encryption` is the key info for server-side-encryption with customer + // provided key. If it is nil, no encryption is performed. + Encryption encrypt.ServerSide + + // `userMeta` is the user-metadata key-value pairs to be set on the + // destination. The keys are automatically prefixed with `x-amz-meta-` + // if needed. If nil is passed, and if only a single source (of any + // size) is provided in the ComposeObject call, then metadata from the + // source is copied to the destination. // if no user-metadata is provided, it is copied from source // (when there is only once source object in the compose // request) - userMetadata map[string]string + UserMeta map[string]string + + // `userTags` is the user defined object tags to be set on destination. + // This will be set only if the `replaceTags` field is set to true. + // Otherwise this field is ignored + UserTags map[string]string + ReplaceTags bool +} + +// Process custom-metadata to remove a `x-amz-meta-` prefix if +// present and validate that keys are distinct (after this +// prefix removal). +func filterCustomMeta(userMeta map[string]string) (map[string]string, error) { + m := make(map[string]string) + for k, v := range userMeta { + if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") { + k = k[len("x-amz-meta-"):] + } + if _, ok := m[k]; ok { + return nil, ErrInvalidArgument(fmt.Sprintf("Cannot add both %s and x-amz-meta-%s keys as custom metadata", k, k)) + } + m[k] = v + } + return m, nil } // NewDestinationInfo - creates a compose-object/copy-source // destination info object. // -// `encSSEC` is the key info for server-side-encryption with customer +// `sse` is the key info for server-side-encryption with customer // provided key. If it is nil, no encryption is performed. // // `userMeta` is the user-metadata key-value pairs to be set on the @@ -63,26 +98,41 @@ func NewDestinationInfo(bucket, object string, sse encrypt.ServerSide, userMeta if err = s3utils.CheckValidObjectName(object); err != nil { return d, err } - - // Process custom-metadata to remove a `x-amz-meta-` prefix if - // present and validate that keys are distinct (after this - // prefix removal). - m := make(map[string]string) - for k, v := range userMeta { - if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") { - k = k[len("x-amz-meta-"):] - } - if _, ok := m[k]; ok { - return d, ErrInvalidArgument(fmt.Sprintf("Cannot add both %s and x-amz-meta-%s keys as custom metadata", k, k)) - } - m[k] = v + m, err := filterCustomMeta(userMeta) + if err != nil { + return d, err } + opts := DestInfoOptions{ + Encryption: sse, + UserMeta: m, + UserTags: nil, + ReplaceTags: false, + } + return DestinationInfo{ + bucket: bucket, + object: object, + opts: opts, + }, nil +} +// NewDestinationInfoWithOptions - creates a compose-object/copy-source +// destination info object. +func NewDestinationInfoWithOptions(bucket, object string, destOpts DestInfoOptions) (d DestinationInfo, err error) { + // Input validation. + if err = s3utils.CheckValidBucketName(bucket); err != nil { + return d, err + } + if err = s3utils.CheckValidObjectName(object); err != nil { + return d, err + } + destOpts.UserMeta, err = filterCustomMeta(destOpts.UserMeta) + if err != nil { + return d, err + } return DestinationInfo{ - bucket: bucket, - object: object, - encryption: sse, - userMetadata: m, + bucket: bucket, + object: object, + opts: destOpts, }, nil } @@ -93,14 +143,14 @@ func NewDestinationInfo(bucket, object string, sse encrypt.ServerSide, userMeta // `REPLACE`, so that metadata headers from the source are not copied // over. func (d *DestinationInfo) getUserMetaHeadersMap(withCopyDirectiveHeader bool) map[string]string { - if len(d.userMetadata) == 0 { + if len(d.opts.UserMeta) == 0 { return nil } r := make(map[string]string) if withCopyDirectiveHeader { r["x-amz-metadata-directive"] = "REPLACE" } - for k, v := range d.userMetadata { + for k, v := range d.opts.UserMeta { if isAmzHeader(k) || isStandardHeader(k) || isStorageClassHeader(k) { r[k] = v } else { @@ -447,7 +497,7 @@ func (c Client) ComposeObjectWithProgress(dst DestinationInfo, srcs []SourceInfo metaHeaders[k] = v } - uploadID, err := c.newUploadID(ctx, dst.bucket, dst.object, PutObjectOptions{ServerSideEncryption: dst.encryption, UserMetadata: metaHeaders}) + uploadID, err := c.newUploadID(ctx, dst.bucket, dst.object, PutObjectOptions{ServerSideEncryption: dst.opts.Encryption, UserMetadata: metaHeaders}) if err != nil { return err } @@ -461,8 +511,8 @@ func (c Client) ComposeObjectWithProgress(dst DestinationInfo, srcs []SourceInfo encrypt.SSECopy(src.encryption).Marshal(h) } // Add destination encryption headers - if dst.encryption != nil { - dst.encryption.Marshal(h) + if dst.opts.Encryption != nil { + dst.opts.Encryption.Marshal(h) } // calculate start/end indices of parts after diff --git a/vendor/github.com/minio/minio-go/v6/api-error-response.go b/vendor/github.com/minio/minio-go/v6/api-error-response.go index 726fdd274a4..4fda64856ec 100644 --- a/vendor/github.com/minio/minio-go/v6/api-error-response.go +++ b/vendor/github.com/minio/minio-go/v6/api-error-response.go @@ -51,6 +51,9 @@ type ErrorResponse struct { // only in HEAD bucket and ListObjects response. Region string + // Captures the server string returned in response header. + Server string + // Underlying HTTP status code for the returned error StatusCode int `xml:"-" json:"-"` } @@ -105,6 +108,7 @@ func httpRespToErrorResponse(resp *http.Response, bucketName, objectName string) errResp := ErrorResponse{ StatusCode: resp.StatusCode, + Server: resp.Header.Get("Server"), } err := xmlDecoder(resp.Body, &errResp) diff --git a/vendor/github.com/minio/minio-go/v6/api-get-bucket-encryption.go b/vendor/github.com/minio/minio-go/v6/api-get-bucket-encryption.go new file mode 100644 index 00000000000..213abb8fc2f --- /dev/null +++ b/vendor/github.com/minio/minio-go/v6/api-get-bucket-encryption.go @@ -0,0 +1,71 @@ +/* + * MinIO Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2020 MinIO, Inc. + * 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 minio + +import ( + "context" + "encoding/xml" + "io/ioutil" + "net/http" + "net/url" + + "github.com/minio/minio-go/v6/pkg/s3utils" +) + +// GetBucketEncryption - get default encryption configuration for a bucket. +func (c Client) GetBucketEncryption(bucketName string) (ServerSideEncryptionConfiguration, error) { + return c.GetBucketEncryptionWithContext(context.Background(), bucketName) +} + +// GetBucketEncryptionWithContext gets the default encryption configuration on an existing bucket with a context to control cancellations and timeouts. +func (c Client) GetBucketEncryptionWithContext(ctx context.Context, bucketName string) (ServerSideEncryptionConfiguration, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return ServerSideEncryptionConfiguration{}, err + } + + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("encryption", "") + + // Execute GET on bucket to get the default encryption configuration. + resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + }) + + defer closeResponse(resp) + if err != nil { + return ServerSideEncryptionConfiguration{}, err + } + + if resp.StatusCode != http.StatusOK { + return ServerSideEncryptionConfiguration{}, httpRespToErrorResponse(resp, bucketName, "") + } + + bucketEncryptionBuf, err := ioutil.ReadAll(resp.Body) + if err != nil { + return ServerSideEncryptionConfiguration{}, err + } + + encryptionConfig := ServerSideEncryptionConfiguration{} + if err := xml.Unmarshal(bucketEncryptionBuf, &encryptionConfig); err != nil { + return ServerSideEncryptionConfiguration{}, err + } + return encryptionConfig, nil +} diff --git a/vendor/github.com/minio/minio-go/v6/api-get-object.go b/vendor/github.com/minio/minio-go/v6/api-get-object.go index 13678280644..c73f4a6b4ff 100644 --- a/vendor/github.com/minio/minio-go/v6/api-get-object.go +++ b/vendor/github.com/minio/minio-go/v6/api-get-object.go @@ -45,6 +45,14 @@ func (c Client) getObjectWithContext(ctx context.Context, bucketName, objectName return nil, err } + // Detect if snowball is server location we are talking to. + var snowball bool + if location, ok := c.bucketLocCache.Get(bucketName); ok { + if location == "snowball" { + snowball = true + } + } + var httpReader io.ReadCloser var objectInfo ObjectInfo var err error @@ -136,7 +144,10 @@ func (c Client) getObjectWithContext(ctx context.Context, bucketName, objectName } else if req.settingObjectInfo { // Request is just to get objectInfo. // Remove range header if already set, for stat Operations to get original file size. delete(opts.headers, "Range") - if etag != "" { + // Check whether this is snowball + // if yes do not use If-Match feature + // it doesn't work. + if etag != "" && !snowball { opts.SetMatchETag(etag) } objectInfo, err := c.statObject(ctx, bucketName, objectName, StatObjectOptions{opts}) @@ -159,7 +170,10 @@ func (c Client) getObjectWithContext(ctx context.Context, bucketName, objectName // new ones when they haven't been already. // All readAt requests are new requests. if req.DidOffsetChange || !req.beenRead { - if etag != "" { + // Check whether this is snowball + // if yes do not use If-Match feature + // it doesn't work. + if etag != "" && !snowball { opts.SetMatchETag(etag) } if httpReader != nil { @@ -622,8 +636,7 @@ func (c Client) getObject(ctx context.Context, bucketName, objectName string, op } // Trim off the odd double quotes from ETag in the beginning and end. - md5sum := strings.TrimPrefix(resp.Header.Get("ETag"), "\"") - md5sum = strings.TrimSuffix(md5sum, "\"") + md5sum := trimEtag(resp.Header.Get("ETag")) // Parse the date. date, err := time.Parse(http.TimeFormat, resp.Header.Get("Last-Modified")) diff --git a/vendor/github.com/minio/minio-go/v6/api-list.go b/vendor/github.com/minio/minio-go/v6/api-list.go index 3329d35fb88..c48201ce760 100644 --- a/vendor/github.com/minio/minio-go/v6/api-list.go +++ b/vendor/github.com/minio/minio-go/v6/api-list.go @@ -19,11 +19,9 @@ package minio import ( "context" - "errors" "fmt" "net/http" "net/url" - "strings" "github.com/minio/minio-go/v6/pkg/s3utils" ) @@ -103,6 +101,12 @@ func (c Client) ListBucketsWithContext(ctx context.Context) ([]BucketInfo, error // func (c Client) ListObjectsV2WithMetadata(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectInfo { + // Check whether this is snowball region, if yes ListObjectsV2 doesn't work, fallback to listObjectsV1. + if location, ok := c.bucketLocCache.Get(bucketName); ok { + if location == "snowball" { + return c.ListObjects(bucketName, objectPrefix, recursive, doneCh) + } + } return c.listObjectsV2(bucketName, objectPrefix, recursive, true, doneCh) } @@ -155,6 +159,7 @@ func (c Client) listObjectsV2(bucketName, objectPrefix string, recursive, metada // If contents are available loop through and send over channel. for _, object := range result.Contents { + object.ETag = trimEtag(object.ETag) select { // Send object content. case objectStatCh <- object: @@ -211,6 +216,12 @@ func (c Client) listObjectsV2(bucketName, objectPrefix string, recursive, metada // } // func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectInfo { + // Check whether this is snowball region, if yes ListObjectsV2 doesn't work, fallback to listObjectsV1. + if location, ok := c.bucketLocCache.Get(bucketName); ok { + if location == "snowball" { + return c.ListObjects(bucketName, objectPrefix, recursive, doneCh) + } + } return c.listObjectsV2(bucketName, objectPrefix, recursive, false, doneCh) } @@ -299,7 +310,10 @@ func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken s // This is an additional verification check to make // sure proper responses are received. if listBucketResult.IsTruncated && listBucketResult.NextContinuationToken == "" { - return listBucketResult, errors.New("Truncated response should have continuation token set") + return listBucketResult, ErrorResponse{ + Code: "NotImplemented", + Message: "Truncated response should have continuation token set", + } } for i, obj := range listBucketResult.Contents { @@ -724,8 +738,7 @@ func (c Client) listObjectParts(bucketName, objectName, uploadID string) (partsI // Append to parts info. for _, part := range listObjPartsResult.ObjectParts { // Trim off the odd double quotes from ETag in the beginning and end. - part.ETag = strings.TrimPrefix(part.ETag, "\"") - part.ETag = strings.TrimSuffix(part.ETag, "\"") + part.ETag = trimEtag(part.ETag) partsInfo[part.PartNumber] = part } // Keep part number marker, for the next iteration. diff --git a/vendor/github.com/minio/minio-go/v6/api-notification.go b/vendor/github.com/minio/minio-go/v6/api-notification.go index 0480c21eb5d..b08ad993a8c 100644 --- a/vendor/github.com/minio/minio-go/v6/api-notification.go +++ b/vendor/github.com/minio/minio-go/v6/api-notification.go @@ -1,6 +1,6 @@ /* * MinIO Go Library for Amazon S3 Compatible Cloud Storage - * Copyright 2017 MinIO, Inc. + * Copyright 2017-2020 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,11 +89,13 @@ type bucketMeta struct { // Notification event object metadata. type objectMeta struct { - Key string `json:"key"` - Size int64 `json:"size,omitempty"` - ETag string `json:"eTag,omitempty"` - VersionID string `json:"versionId,omitempty"` - Sequencer string `json:"sequencer"` + Key string `json:"key"` + Size int64 `json:"size,omitempty"` + ETag string `json:"eTag,omitempty"` + ContentType string `json:"contentType,omitempty"` + UserMetadata map[string]string `json:"userMetadata,omitempty"` + VersionID string `json:"versionId,omitempty"` + Sequencer string `json:"sequencer"` } // Notification event server specific metadata. diff --git a/vendor/github.com/minio/minio-go/v6/api-object-legal-hold.go b/vendor/github.com/minio/minio-go/v6/api-object-legal-hold.go new file mode 100644 index 00000000000..2b43575aced --- /dev/null +++ b/vendor/github.com/minio/minio-go/v6/api-object-legal-hold.go @@ -0,0 +1,176 @@ +/* + * MinIO Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2020 MinIO, Inc. + * + * 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 minio + +import ( + "bytes" + "context" + "encoding/xml" + "fmt" + "net/http" + "net/url" + + "github.com/minio/minio-go/v6/pkg/s3utils" +) + +// objectLegalHold - object legal hold specified in +// https://docs.aws.amazon.com/AmazonS3/latest/API/archive-RESTObjectPUTLegalHold.html +type objectLegalHold struct { + XMLNS string `xml:"xmlns,attr,omitempty"` + XMLName xml.Name `xml:"LegalHold"` + Status LegalHoldStatus `xml:"Status,omitempty"` +} + +// PutObjectLegalHoldOptions represents options specified by user for PutObjectLegalHold call +type PutObjectLegalHoldOptions struct { + VersionID string + Status *LegalHoldStatus +} + +// GetObjectLegalHoldOptions represents options specified by user for GetObjectLegalHold call +type GetObjectLegalHoldOptions struct { + VersionID string +} + +// LegalHoldStatus - object legal hold status. +type LegalHoldStatus string + +const ( + // LegalHoldEnabled indicates legal hold is enabled + LegalHoldEnabled LegalHoldStatus = "ON" + + // LegalHoldDisabled indicates legal hold is disabled + LegalHoldDisabled LegalHoldStatus = "OFF" +) + +func (r LegalHoldStatus) String() string { + return string(r) +} + +// IsValid - check whether this legal hold status is valid or not. +func (r LegalHoldStatus) IsValid() bool { + return r == LegalHoldEnabled || r == LegalHoldDisabled +} + +func newObjectLegalHold(status *LegalHoldStatus) (*objectLegalHold, error) { + if status == nil { + return nil, fmt.Errorf("Status not set") + } + if !status.IsValid() { + return nil, fmt.Errorf("invalid legal hold status `%v`", status) + } + legalHold := &objectLegalHold{ + Status: *status, + } + return legalHold, nil +} + +// PutObjectLegalHold : sets object legal hold for a given object and versionID. +func (c Client) PutObjectLegalHold(bucketName, objectName string, opts PutObjectLegalHoldOptions) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return err + } + + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("legal-hold", "") + + if opts.VersionID != "" { + urlValues.Set("versionId", opts.VersionID) + } + + lh, err := newObjectLegalHold(opts.Status) + if err != nil { + return err + } + + lhData, err := xml.Marshal(lh) + if err != nil { + return err + } + + reqMetadata := requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + contentBody: bytes.NewReader(lhData), + contentLength: int64(len(lhData)), + contentMD5Base64: sumMD5Base64(lhData), + contentSHA256Hex: sum256Hex(lhData), + } + + // Execute PUT Object Legal Hold. + resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata) + defer closeResponse(resp) + if err != nil { + return err + } + if resp != nil { + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { + return httpRespToErrorResponse(resp, bucketName, objectName) + } + } + return nil +} + +// GetObjectLegalHold gets legal-hold status of given object. +func (c Client) GetObjectLegalHold(bucketName, objectName string, opts GetObjectLegalHoldOptions) (status *LegalHoldStatus, err error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return nil, err + } + + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return nil, err + } + urlValues := make(url.Values) + urlValues.Set("legal-hold", "") + + if opts.VersionID != "" { + urlValues.Set("versionId", opts.VersionID) + } + + // Execute GET on bucket to list objects. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return nil, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return nil, httpRespToErrorResponse(resp, bucketName, objectName) + } + } + lh := &objectLegalHold{} + if err = xml.NewDecoder(resp.Body).Decode(lh); err != nil { + return nil, err + } + + return &lh.Status, nil +} diff --git a/vendor/github.com/minio/minio-go/v6/api-object-tagging.go b/vendor/github.com/minio/minio-go/v6/api-object-tagging.go new file mode 100644 index 00000000000..fdf8fab91a4 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v6/api-object-tagging.go @@ -0,0 +1,163 @@ +/* + * MinIO Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2020 MinIO, Inc. + * + * 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 minio + +import ( + "bytes" + "context" + "encoding/xml" + "io/ioutil" + "net/http" + "net/url" + + "github.com/minio/minio-go/v6/pkg/s3utils" +) + +// PutObjectTagging replaces or creates object tag(s) +func (c Client) PutObjectTagging(bucketName, objectName string, objectTags map[string]string) error { + return c.PutObjectTaggingWithContext(context.Background(), bucketName, objectName, objectTags) +} + +// PutObjectTaggingWithContext replaces or creates object tag(s) with a context to control cancellations +// and timeouts. +func (c Client) PutObjectTaggingWithContext(ctx context.Context, bucketName, objectName string, objectTags map[string]string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("tagging", "") + + tags := make([]tag, 0) + for k, v := range objectTags { + t := tag{ + Key: k, + Value: v, + } + tags = append(tags, t) + } + + // Prepare Tagging struct + reqBody := tagging{ + TagSet: tagSet{ + Tags: tags, + }, + } + + reqBytes, err := xml.Marshal(reqBody) + if err != nil { + return err + } + + reqMetadata := requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + contentBody: bytes.NewReader(reqBytes), + contentLength: int64(len(reqBytes)), + contentMD5Base64: sumMD5Base64(reqBytes), + } + + // Execute PUT to set a object tagging. + resp, err := c.executeMethod(ctx, "PUT", reqMetadata) + defer closeResponse(resp) + if err != nil { + return err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return httpRespToErrorResponse(resp, bucketName, objectName) + } + } + return nil +} + +// GetObjectTagging fetches object tag(s) +func (c Client) GetObjectTagging(bucketName, objectName string) (string, error) { + return c.GetObjectTaggingWithContext(context.Background(), bucketName, objectName) +} + +// GetObjectTaggingWithContext fetches object tag(s) with a context to control cancellations +// and timeouts. +func (c Client) GetObjectTaggingWithContext(ctx context.Context, bucketName, objectName string) (string, error) { + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("tagging", "") + + // Execute GET on object to get object tag(s) + resp, err := c.executeMethod(ctx, "GET", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + }) + + defer closeResponse(resp) + if err != nil { + return "", err + } + + if resp != nil { + if resp.StatusCode != http.StatusOK { + return "", httpRespToErrorResponse(resp, bucketName, objectName) + } + } + + tagBuf, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(tagBuf), err +} + +// RemoveObjectTagging deletes object tag(s) +func (c Client) RemoveObjectTagging(bucketName, objectName string) error { + return c.RemoveObjectTaggingWithContext(context.Background(), bucketName, objectName) +} + +// RemoveObjectTaggingWithContext removes object tag(s) with a context to control cancellations +// and timeouts. +func (c Client) RemoveObjectTaggingWithContext(ctx context.Context, bucketName, objectName string) error { + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("tagging", "") + + // Execute DELETE on object to remove object tag(s) + resp, err := c.executeMethod(ctx, "DELETE", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + }) + + defer closeResponse(resp) + if err != nil { + return err + } + + if resp != nil { + if resp.StatusCode != http.StatusOK { + return httpRespToErrorResponse(resp, bucketName, objectName) + } + } + return err +} diff --git a/vendor/github.com/minio/minio-go/v6/api-put-bucket.go b/vendor/github.com/minio/minio-go/v6/api-put-bucket.go index 68371986ae8..8d9671b1e1c 100644 --- a/vendor/github.com/minio/minio-go/v6/api-put-bucket.go +++ b/vendor/github.com/minio/minio-go/v6/api-put-bucket.go @@ -1,6 +1,6 @@ /* * MinIO Go Library for Amazon S3 Compatible Cloud Storage - * Copyright 2015-2017 MinIO, Inc. + * Copyright 2015-2020 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,25 @@ import ( "github.com/minio/minio-go/v6/pkg/s3utils" ) +// ApplyServerSideEncryptionByDefault defines default encryption configuration, KMS or SSE. To activate +// KMS, SSEAlgoritm needs to be set to "aws:kms" +// Minio currently does not support Kms. +type ApplyServerSideEncryptionByDefault struct { + KmsMasterKeyID string `xml:"KMSMasterKeyID,omitempty"` + SSEAlgorithm string `xml:"SSEAlgorithm"` +} + +// Rule layer encapsulates default encryption configuration +type Rule struct { + Apply ApplyServerSideEncryptionByDefault `xml:"ApplyServerSideEncryptionByDefault"` +} + +// ServerSideEncryptionConfiguration is the default encryption configuration structure +type ServerSideEncryptionConfiguration struct { + XMLName xml.Name `xml:"ServerSideEncryptionConfiguration"` + Rules []Rule `xml:"Rule"` +} + /// Bucket operations func (c Client) makeBucket(ctx context.Context, bucketName string, location string, objectLockEnabled bool) (err error) { @@ -313,6 +332,82 @@ func (c Client) removeBucketLifecycle(ctx context.Context, bucketName string) er return nil } +// SetBucketEncryption sets the default encryption configuration on an existing bucket. +func (c Client) SetBucketEncryption(bucketName string, configuration ServerSideEncryptionConfiguration) error { + return c.SetBucketEncryptionWithContext(context.Background(), bucketName, configuration) +} + +// SetBucketEncryptionWithContext sets the default encryption configuration on an existing bucket with a context to control cancellations and timeouts. +func (c Client) SetBucketEncryptionWithContext(ctx context.Context, bucketName string, configuration ServerSideEncryptionConfiguration) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + buf, err := xml.Marshal(&configuration) + if err != nil { + return err + } + + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("encryption", "") + + // Content-length is mandatory to set a default encryption configuration + reqMetadata := requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentBody: bytes.NewReader(buf), + contentLength: int64(len(buf)), + contentMD5Base64: sumMD5Base64(buf), + } + + // Execute PUT to upload a new bucket default encryption configuration. + resp, err := c.executeMethod(ctx, http.MethodPut, reqMetadata) + defer closeResponse(resp) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + return httpRespToErrorResponse(resp, bucketName, "") + } + return nil +} + +// DeleteBucketEncryption removes the default encryption configuration on a bucket. +func (c Client) DeleteBucketEncryption(bucketName string) error { + return c.DeleteBucketEncryptionWithContext(context.Background(), bucketName) +} + +// DeleteBucketEncryptionWithContext removes the default encryption configuration on a bucket with a context to control cancellations and timeouts. +func (c Client) DeleteBucketEncryptionWithContext(ctx context.Context, bucketName string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("encryption", "") + + // DELETE default encryption configuration on a bucket. + resp, err := c.executeMethod(ctx, http.MethodDelete, requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { + return httpRespToErrorResponse(resp, bucketName, "") + } + return nil +} + // SetBucketNotification saves a new bucket notification. func (c Client) SetBucketNotification(bucketName string, bucketNotification BucketNotification) error { return c.SetBucketNotificationWithContext(context.Background(), bucketName, bucketNotification) diff --git a/vendor/github.com/minio/minio-go/v6/api-put-object-common.go b/vendor/github.com/minio/minio-go/v6/api-put-object-common.go index a786d2a8e08..78e0a2fdcd6 100644 --- a/vendor/github.com/minio/minio-go/v6/api-put-object-common.go +++ b/vendor/github.com/minio/minio-go/v6/api-put-object-common.go @@ -69,7 +69,9 @@ func isReadAt(reader io.Reader) (ok bool) { // func optimalPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCount int, partSize int64, lastPartSize int64, err error) { // object size is '-1' set it to 5TiB. + var unknownSize bool if objectSize == -1 { + unknownSize = true objectSize = maxMultipartPutObjectSize } @@ -86,9 +88,11 @@ func optimalPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCou return } - if objectSize > (int64(configuredPartSize) * maxPartsCount) { - err = ErrInvalidArgument("Part size * max_parts(10000) is lesser than input objectSize.") - return + if !unknownSize { + if objectSize > (int64(configuredPartSize) * maxPartsCount) { + err = ErrInvalidArgument("Part size * max_parts(10000) is lesser than input objectSize.") + return + } } if configuredPartSize < absMinPartSize { @@ -100,7 +104,13 @@ func optimalPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCou err = ErrInvalidArgument("Input part size is bigger than allowed maximum of 5GiB.") return } + partSizeFlt = float64(configuredPartSize) + if unknownSize { + // If input has unknown size and part size is configured + // keep it to maximum allowed as per 10000 parts. + objectSize = int64(configuredPartSize) * maxPartsCount + } } else { configuredPartSize = minPartSize // Use floats for part size for all calculations to avoid diff --git a/vendor/github.com/minio/minio-go/v6/api-put-object-copy.go b/vendor/github.com/minio/minio-go/v6/api-put-object-copy.go index 19e58add89e..ce48674b04d 100644 --- a/vendor/github.com/minio/minio-go/v6/api-put-object-copy.go +++ b/vendor/github.com/minio/minio-go/v6/api-put-object-copy.go @@ -24,6 +24,7 @@ import ( "net/http" "github.com/minio/minio-go/v6/pkg/encrypt" + "github.com/minio/minio-go/v6/pkg/s3utils" ) // CopyObject - copy a source object into a new object @@ -39,6 +40,11 @@ func (c Client) CopyObjectWithProgress(dst DestinationInfo, src SourceInfo, prog header[k] = v } + if dst.opts.ReplaceTags && len(dst.opts.UserTags) != 0 { + header.Set(amzTaggingHeaderDirective, "REPLACE") + header.Set(amzTaggingHeader, s3utils.TagEncode(dst.opts.UserTags)) + } + var err error var size int64 // If progress bar is specified, size should be requested as well initiate a StatObject request. @@ -53,8 +59,8 @@ func (c Client) CopyObjectWithProgress(dst DestinationInfo, src SourceInfo, prog encrypt.SSECopy(src.encryption).Marshal(header) } - if dst.encryption != nil { - dst.encryption.Marshal(header) + if dst.opts.Encryption != nil { + dst.opts.Encryption.Marshal(header) } for k, v := range dst.getUserMetaHeadersMap(true) { header.Set(k, v) diff --git a/vendor/github.com/minio/minio-go/v6/api-put-object-multipart.go b/vendor/github.com/minio/minio-go/v6/api-put-object-multipart.go index ab284f98695..864acc8bcb5 100644 --- a/vendor/github.com/minio/minio-go/v6/api-put-object-multipart.go +++ b/vendor/github.com/minio/minio-go/v6/api-put-object-multipart.go @@ -137,11 +137,10 @@ func (c Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obje } // Proceed to upload the part. - var objPart ObjectPart - objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber, + objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber, md5Base64, sha256Hex, int64(length), opts.ServerSideEncryption) - if err != nil { - return totalUploadedSize, err + if uerr != nil { + return totalUploadedSize, uerr } // Save successfully uploaded part metadata. @@ -294,8 +293,7 @@ func (c Client) uploadPart(ctx context.Context, bucketName, objectName, uploadID objPart.Size = size objPart.PartNumber = partNumber // Trim off the odd double quotes from ETag in the beginning and end. - objPart.ETag = strings.TrimPrefix(resp.Header.Get("ETag"), "\"") - objPart.ETag = strings.TrimSuffix(objPart.ETag, "\"") + objPart.ETag = trimEtag(resp.Header.Get("ETag")) return objPart, nil } diff --git a/vendor/github.com/minio/minio-go/v6/api-put-object-streaming.go b/vendor/github.com/minio/minio-go/v6/api-put-object-streaming.go index 0d3f2455a7c..5add2afcfc2 100644 --- a/vendor/github.com/minio/minio-go/v6/api-put-object-streaming.go +++ b/vendor/github.com/minio/minio-go/v6/api-put-object-streaming.go @@ -67,12 +67,12 @@ type uploadedPartRes struct { Error error // Any error encountered while uploading the part. PartNum int // Number of the part uploaded. Size int64 // Size of the part uploaded. - Part *ObjectPart + Part ObjectPart } type uploadPartReq struct { - PartNum int // Number of the part uploaded. - Part *ObjectPart // Size of the part uploaded. + PartNum int // Number of the part uploaded. + Part ObjectPart // Size of the part uploaded. } // putObjectMultipartFromReadAt - Uploads files bigger than 128MiB. @@ -139,7 +139,7 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa // Send each part number to the channel to be processed. for p := 1; p <= totalPartsCount; p++ { - uploadPartsCh <- uploadPartReq{PartNum: p, Part: nil} + uploadPartsCh <- uploadPartReq{PartNum: p} } close(uploadPartsCh) // Receive each part number from the channel allowing three parallel uploads. @@ -164,13 +164,11 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa sectionReader := newHook(io.NewSectionReader(reader, readOffset, partSize), opts.Progress) // Proceed to upload the part. - var objPart ObjectPart - objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, + objPart, err := c.uploadPart(ctx, bucketName, objectName, uploadID, sectionReader, uploadReq.PartNum, "", "", partSize, opts.ServerSideEncryption) if err != nil { uploadedPartsCh <- uploadedPartRes{ - Size: 0, Error: err, } // Exit the goroutine. @@ -178,14 +176,13 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa } // Save successfully uploaded part metadata. - uploadReq.Part = &objPart + uploadReq.Part = objPart // Send successful part info through the channel. uploadedPartsCh <- uploadedPartRes{ Size: objPart.Size, PartNum: uploadReq.PartNum, Part: uploadReq.Part, - Error: nil, } } }(partSize) @@ -198,18 +195,12 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa if uploadRes.Error != nil { return totalUploadedSize, uploadRes.Error } - // Retrieve each uploaded part and store it to be completed. - // part, ok := partsInfo[uploadRes.PartNum] - part := uploadRes.Part - if part == nil { - return 0, ErrInvalidArgument(fmt.Sprintf("Missing part number %d", uploadRes.PartNum)) - } // Update the totalUploadedSize. totalUploadedSize += uploadRes.Size // Store the parts to be completed in order. complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{ - ETag: part.ETag, - PartNumber: part.PartNumber, + ETag: uploadRes.Part.ETag, + PartNumber: uploadRes.Part.PartNumber, }) } @@ -277,12 +268,11 @@ func (c Client) putObjectMultipartStreamNoChecksum(ctx context.Context, bucketNa if partNumber == totalPartsCount { partSize = lastPartSize } - var objPart ObjectPart - objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, + objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID, io.LimitReader(hookReader, partSize), partNumber, "", "", partSize, opts.ServerSideEncryption) - if err != nil { - return totalUploadedSize, err + if uerr != nil { + return totalUploadedSize, uerr } // Save successfully uploaded part metadata. @@ -407,8 +397,7 @@ func (c Client) putObjectDo(ctx context.Context, bucketName, objectName string, var objInfo ObjectInfo // Trim off the odd double quotes from ETag in the beginning and end. - objInfo.ETag = strings.TrimPrefix(resp.Header.Get("ETag"), "\"") - objInfo.ETag = strings.TrimSuffix(objInfo.ETag, "\"") + objInfo.ETag = trimEtag(resp.Header.Get("ETag")) // A success here means data was written to server successfully. objInfo.Size = size diff --git a/vendor/github.com/minio/minio-go/v6/api-put-object.go b/vendor/github.com/minio/minio-go/v6/api-put-object.go index bc0848bbfc4..c760056cb6d 100644 --- a/vendor/github.com/minio/minio-go/v6/api-put-object.go +++ b/vendor/github.com/minio/minio-go/v6/api-put-object.go @@ -35,6 +35,7 @@ import ( // PutObjectOptions represents options specified by user for PutObject call type PutObjectOptions struct { UserMetadata map[string]string + UserTags map[string]string Progress io.Reader ContentType string ContentEncoding string @@ -100,6 +101,9 @@ func (opts PutObjectOptions) Header() (header http.Header) { if opts.WebsiteRedirectLocation != "" { header[amzWebsiteRedirectLocation] = []string{opts.WebsiteRedirectLocation} } + if len(opts.UserTags) != 0 { + header[amzTaggingHeader] = []string{s3utils.TagEncode(opts.UserTags)} + } for k, v := range opts.UserMetadata { if !isAmzHeader(k) && !isStandardHeader(k) && !isStorageClassHeader(k) { header["X-Amz-Meta-"+k] = []string{v} @@ -231,23 +235,23 @@ func (c Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketName defer debug.FreeOSMemory() for partNumber <= totalPartsCount { - length, rErr := io.ReadFull(reader, buf) - if rErr == io.EOF && partNumber > 1 { + length, rerr := io.ReadFull(reader, buf) + if rerr == io.EOF && partNumber > 1 { break } - if rErr != nil && rErr != io.ErrUnexpectedEOF && rErr != io.EOF { - return 0, rErr + if rerr != nil && rerr != io.ErrUnexpectedEOF && rerr != io.EOF { + return 0, rerr } + // Update progress reader appropriately to the latest offset // as we read from the source. rd := newHook(bytes.NewReader(buf[:length]), opts.Progress) // Proceed to upload the part. - var objPart ObjectPart - objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber, + objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber, "", "", int64(length), opts.ServerSideEncryption) - if err != nil { - return totalUploadedSize, err + if uerr != nil { + return totalUploadedSize, uerr } // Save successfully uploaded part metadata. @@ -261,7 +265,7 @@ func (c Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketName // For unknown size, Read EOF we break away. // We do not have to upload till totalPartsCount. - if rErr == io.EOF { + if rerr == io.EOF { break } } diff --git a/vendor/github.com/minio/minio-go/v6/api-s3-datatypes.go b/vendor/github.com/minio/minio-go/v6/api-s3-datatypes.go index a6b125522a8..deb56e39d98 100644 --- a/vendor/github.com/minio/minio-go/v6/api-s3-datatypes.go +++ b/vendor/github.com/minio/minio-go/v6/api-s3-datatypes.go @@ -243,3 +243,19 @@ type deleteMultiObjectsResult struct { DeletedObjects []deletedObject `xml:"Deleted"` UnDeletedObjects []nonDeletedObject `xml:"Error"` } + +type tagging struct { + XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ Tagging"` + TagSet tagSet +} + +type tagSet struct { + XMLName xml.Name `xml:"TagSet"` + Tags []tag +} + +type tag struct { + XMLName xml.Name `xml:"Tag"` + Key string `xml:"Key"` + Value string `xml:"Value"` +} diff --git a/vendor/github.com/minio/minio-go/v6/api-stat.go b/vendor/github.com/minio/minio-go/v6/api-stat.go index fe246e318e2..45844c9cb10 100644 --- a/vendor/github.com/minio/minio-go/v6/api-stat.go +++ b/vendor/github.com/minio/minio-go/v6/api-stat.go @@ -78,7 +78,7 @@ var defaultFilterKeys = []string{ "x-amz-id-2", "Content-Security-Policy", "X-Xss-Protection", - + amzTaggingHeaderCount, // Add new headers to be ignored. } @@ -91,6 +91,8 @@ func extractObjMetadata(header http.Header) http.Header { "Last-Modified", "Content-Type", "Expires", + "X-Cache", + "X-Cache-Lookup", }, defaultFilterKeys...) return filterHeader(header, filterKeys) } @@ -141,8 +143,7 @@ func (c Client) statObject(ctx context.Context, bucketName, objectName string, o } // Trim off the odd double quotes from ETag in the beginning and end. - md5sum := strings.TrimPrefix(resp.Header.Get("ETag"), "\"") - md5sum = strings.TrimSuffix(md5sum, "\"") + md5sum := trimEtag(resp.Header.Get("ETag")) // Parse content length is exists var size int64 = -1 diff --git a/vendor/github.com/minio/minio-go/v6/api.go b/vendor/github.com/minio/minio-go/v6/api.go index f0978b63364..d9fc59a51b0 100644 --- a/vendor/github.com/minio/minio-go/v6/api.go +++ b/vendor/github.com/minio/minio-go/v6/api.go @@ -104,7 +104,7 @@ type Options struct { // Global constants. const ( libraryName = "minio-go" - libraryVersion = "v6.0.44" + libraryVersion = "v6.0.49" ) // User Agent should always following the below style. @@ -560,6 +560,13 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque var bodySeeker io.Seeker // Extracted seeker from io.Reader. var reqRetry = MaxRetry // Indicates how many times we can retry the request + defer func() { + if err != nil { + // close idle connections before returning, upon error. + c.httpClient.CloseIdleConnections() + } + }() + if metadata.contentBody != nil { // Check if body is seekable then it is retryable. bodySeeker, isRetryable = metadata.contentBody.(io.Seeker) @@ -620,12 +627,7 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque // Initiate the request. res, err = c.do(req) if err != nil { - // For supported http requests errors verify. - if isHTTPReqErrorRetryable(err) { - continue // Retry. - } - // For other errors, return here no need to retry. - return nil, err + continue } // For any known successful http status, return quickly. @@ -667,20 +669,23 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque case "InvalidRegion": fallthrough case "AccessDenied": - if metadata.bucketName != "" && errResponse.Region != "" { + if errResponse.Region == "" { + // Region is empty we simply return the error. + return res, err + } + // Region is not empty figure out a way to + // handle this appropriately. + if metadata.bucketName != "" { // Gather Cached location only if bucketName is present. if _, cachedOk := c.bucketLocCache.Get(metadata.bucketName); cachedOk { c.bucketLocCache.Set(metadata.bucketName, errResponse.Region) continue // Retry. } } else { - // Most probably for ListBuckets() + // This is for ListBuckets() fallback. if errResponse.Region != metadata.bucketLocation { - // Retry if the error - // response has a - // different region - // than the request we - // just made. + // Retry if the error response has a different region + // than the request we just made. metadata.bucketLocation = errResponse.Region continue // Retry } @@ -822,7 +827,7 @@ func (c Client) newRequest(method string, metadata requestMetadata) (req *http.R case signerType.IsV2(): // Add signature version '2' authorization header. req = s3signer.SignV2(*req, accessKeyID, secretAccessKey, isVirtualHost) - case metadata.objectName != "" && method == "PUT" && metadata.customHeader.Get("X-Amz-Copy-Source") == "" && !c.secure: + case metadata.objectName != "" && metadata.queryValues == nil && method == "PUT" && metadata.customHeader.Get("X-Amz-Copy-Source") == "" && !c.secure: // Streaming signature is used by default for a PUT object request. Additionally we also // look if the initialized client is secure, if yes then we don't need to perform // streaming signature. diff --git a/vendor/github.com/minio/minio-go/v6/bucket-cache.go b/vendor/github.com/minio/minio-go/v6/bucket-cache.go index 7ba6cbb5711..5e46bf9a738 100644 --- a/vendor/github.com/minio/minio-go/v6/bucket-cache.go +++ b/vendor/github.com/minio/minio-go/v6/bucket-cache.go @@ -125,6 +125,10 @@ func processBucketLocationResponse(resp *http.Response, bucketName string) (buck // request. Move forward and let the top level callers // succeed if possible based on their policy. switch errResp.Code { + case "NotImplemented": + if errResp.Server == "AmazonSnowball" { + return "snowball", nil + } case "AuthorizationHeaderMalformed": fallthrough case "InvalidRegion": diff --git a/vendor/github.com/minio/minio-go/v6/constants.go b/vendor/github.com/minio/minio-go/v6/constants.go index ac472a631d1..7f907c8b2c4 100644 --- a/vendor/github.com/minio/minio-go/v6/constants.go +++ b/vendor/github.com/minio/minio-go/v6/constants.go @@ -60,3 +60,8 @@ const amzStorageClass = "X-Amz-Storage-Class" // Website redirect location header constant const amzWebsiteRedirectLocation = "X-Amz-Website-Redirect-Location" + +// Tagging header constants +const amzTaggingHeader = "X-Amz-Tagging" +const amzTaggingHeaderDirective = "X-Amz-Tagging-Directive" +const amzTaggingHeaderCount = "X-Amz-Tagging-Count" diff --git a/vendor/github.com/minio/minio-go/v6/pkg/credentials/iam_aws.go b/vendor/github.com/minio/minio-go/v6/pkg/credentials/iam_aws.go index 34c593fdf5a..1b67cbfad92 100644 --- a/vendor/github.com/minio/minio-go/v6/pkg/credentials/iam_aws.go +++ b/vendor/github.com/minio/minio-go/v6/pkg/credentials/iam_aws.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + "io/ioutil" "net" "net/http" "net/url" @@ -54,41 +55,10 @@ type IAM struct { const ( defaultIAMRoleEndpoint = "http://169.254.169.254" defaultECSRoleEndpoint = "http://169.254.170.2" + defaultSTSRoleEndpoint = "https://sts.amazonaws.com" defaultIAMSecurityCredsPath = "/latest/meta-data/iam/security-credentials/" ) -// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html -func getEndpoint(endpoint string) (string, bool, error) { - ecsFullURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_FULL_URI") - ecsURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") - - if endpoint != "" { - return endpoint, ecsURI != "" || ecsFullURI != "", nil - } - if ecsFullURI != "" { - u, err := url.Parse(ecsFullURI) - if err != nil { - return "", false, err - } - host := u.Hostname() - if host == "" { - return "", false, fmt.Errorf("can't parse host from uri: %s", ecsFullURI) - } - - if loopback, err := isLoopback(host); loopback { - return ecsFullURI, true, nil - } else if err != nil { - return "", false, err - } else { - return "", false, fmt.Errorf("host is not on a loopback address: %s", host) - } - } - if ecsURI != "" { - return fmt.Sprintf("%s%s", defaultECSRoleEndpoint, ecsURI), true, nil - } - return defaultIAMRoleEndpoint, false, nil -} - // NewIAM returns a pointer to a new Credentials object wrapping the IAM. func NewIAM(endpoint string) *Credentials { p := &IAM{ @@ -107,16 +77,61 @@ func (m *IAM) Retrieve() (Value, error) { var roleCreds ec2RoleCredRespBody var err error - endpoint, isEcsTask, err := getEndpoint(m.endpoint) - if err != nil { - return Value{}, err - } + endpoint := m.endpoint + switch { + case len(os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")) > 0: + if len(endpoint) == 0 { + if len(os.Getenv("AWS_REGION")) > 0 { + endpoint = "sts." + os.Getenv("AWS_REGION") + ".amazonaws.com" + } else { + endpoint = defaultSTSRoleEndpoint + } + } + + creds := &STSWebIdentity{ + Client: m.Client, + stsEndpoint: endpoint, + roleARN: os.Getenv("AWS_ROLE_ARN"), + roleSessionName: os.Getenv("AWS_ROLE_SESSION_NAME"), + getWebIDTokenExpiry: func() (*WebIdentityToken, error) { + token, err := ioutil.ReadFile(os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")) + if err != nil { + return nil, err + } + + return &WebIdentityToken{Token: string(token)}, nil + }, + } + + return creds.Retrieve() + + case len(os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")) > 0: + if len(endpoint) == 0 { + endpoint = fmt.Sprintf("%s%s", defaultECSRoleEndpoint, + os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")) + } + + roleCreds, err = getEcsTaskCredentials(m.Client, endpoint) + + case len(os.Getenv("AWS_CONTAINER_CREDENTIALS_FULL_URI")) > 0: + if len(endpoint) == 0 { + endpoint = os.Getenv("AWS_CONTAINER_CREDENTIALS_FULL_URI") + + var ok bool + if ok, err = isLoopback(endpoint); !ok { + if err == nil { + err = fmt.Errorf("uri host is not a loopback address: %s", endpoint) + } + break + } + } - if isEcsTask { roleCreds, err = getEcsTaskCredentials(m.Client, endpoint) - } else { + + default: roleCreds, err = getCredentials(m.Client, endpoint) } + if err != nil { return Value{}, err } @@ -153,6 +168,10 @@ type ec2RoleCredRespBody struct { // be sent to fetch the rolling access credentials. // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html func getIAMRoleURL(endpoint string) (*url.URL, error) { + if endpoint == "" { + endpoint = defaultIAMRoleEndpoint + } + u, err := url.Parse(endpoint) if err != nil { return nil, err @@ -276,8 +295,18 @@ func getCredentials(client *http.Client, endpoint string) (ec2RoleCredRespBody, return respCreds, nil } -// isLoopback identifies if a host is on a loopback address -func isLoopback(host string) (bool, error) { +// isLoopback identifies if a uri's host is on a loopback address +func isLoopback(uri string) (bool, error) { + u, err := url.Parse(uri) + if err != nil { + return false, err + } + + host := u.Hostname() + if len(host) == 0 { + return false, fmt.Errorf("can't parse host from uri: %s", uri) + } + ips, err := net.LookupHost(host) if err != nil { return false, err diff --git a/vendor/github.com/minio/minio-go/v6/pkg/credentials/sts_web_identity.go b/vendor/github.com/minio/minio-go/v6/pkg/credentials/sts_web_identity.go index 4d53bd23674..216f48ac37e 100644 --- a/vendor/github.com/minio/minio-go/v6/pkg/credentials/sts_web_identity.go +++ b/vendor/github.com/minio/minio-go/v6/pkg/credentials/sts_web_identity.go @@ -23,6 +23,7 @@ import ( "fmt" "net/http" "net/url" + "strconv" "time" ) @@ -75,6 +76,13 @@ type STSWebIdentity struct { // this token. // This is a customer provided function and is mandatory. getWebIDTokenExpiry func() (*WebIdentityToken, error) + + // roleARN is the Amazon Resource Name (ARN) of the role that the caller is + // assuming. + roleARN string + + // roleSessionName is the identifier for the assumed role session. + roleSessionName string } // NewSTSWebIdentity returns a pointer to a new @@ -95,7 +103,7 @@ func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdent }), nil } -func getWebIdentityCredentials(clnt *http.Client, endpoint string, +func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSessionName string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (AssumeRoleWithWebIdentityResponse, error) { idToken, err := getWebIDTokenExpiry() if err != nil { @@ -104,8 +112,18 @@ func getWebIdentityCredentials(clnt *http.Client, endpoint string, v := url.Values{} v.Set("Action", "AssumeRoleWithWebIdentity") + if len(roleARN) > 0 { + v.Set("RoleArn", roleARN) + + if len(roleSessionName) == 0 { + roleSessionName = strconv.FormatInt(time.Now().UnixNano(), 10) + } + v.Set("RoleSessionName", roleSessionName) + } v.Set("WebIdentityToken", idToken.Token) - v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry)) + if idToken.Expiry > 0 { + v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry)) + } v.Set("Version", "2011-06-15") u, err := url.Parse(endpoint) @@ -141,7 +159,7 @@ func getWebIdentityCredentials(clnt *http.Client, endpoint string, // Retrieve retrieves credentials from the MinIO service. // Error will be returned if the request fails. func (m *STSWebIdentity) Retrieve() (Value, error) { - a, err := getWebIdentityCredentials(m.Client, m.stsEndpoint, m.getWebIDTokenExpiry) + a, err := getWebIdentityCredentials(m.Client, m.stsEndpoint, m.roleARN, m.roleSessionName, m.getWebIDTokenExpiry) if err != nil { return Value{}, err } diff --git a/vendor/github.com/minio/minio-go/v6/pkg/encrypt/server-side.go b/vendor/github.com/minio/minio-go/v6/pkg/encrypt/server-side.go index ac0b69a02aa..cabc65067d7 100644 --- a/vendor/github.com/minio/minio-go/v6/pkg/encrypt/server-side.go +++ b/vendor/github.com/minio/minio-go/v6/pkg/encrypt/server-side.go @@ -188,7 +188,9 @@ func (s kms) Type() Type { return KMS } func (s kms) Marshal(h http.Header) { h.Set(sseGenericHeader, "aws:kms") - h.Set(sseKmsKeyID, s.key) + if s.key != "" { + h.Set(sseKmsKeyID, s.key) + } if s.hasContext { h.Set(sseEncryptionContext, base64.StdEncoding.EncodeToString(s.context)) } diff --git a/vendor/github.com/minio/minio-go/v6/pkg/s3utils/utils.go b/vendor/github.com/minio/minio-go/v6/pkg/s3utils/utils.go index 9af2997b745..982dddf4bbf 100644 --- a/vendor/github.com/minio/minio-go/v6/pkg/s3utils/utils.go +++ b/vendor/github.com/minio/minio-go/v6/pkg/s3utils/utils.go @@ -84,16 +84,22 @@ func IsVirtualHostSupported(endpointURL url.URL, bucketName string) bool { // Refer for region styles - https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region // amazonS3HostHyphen - regular expression used to determine if an arg is s3 host in hyphenated style. -var amazonS3HostHyphen = regexp.MustCompile(`^s3-(.*?)\.amazonaws\.com$`) +var amazonS3HostHyphen = regexp.MustCompile(`^s3-(.*?).amazonaws.com$`) // amazonS3HostDualStack - regular expression used to determine if an arg is s3 host dualstack. -var amazonS3HostDualStack = regexp.MustCompile(`^s3\.dualstack\.(.*?)\.amazonaws\.com$`) +var amazonS3HostDualStack = regexp.MustCompile(`^s3.dualstack.(.*?).amazonaws.com$`) // amazonS3HostDot - regular expression used to determine if an arg is s3 host in . style. -var amazonS3HostDot = regexp.MustCompile(`^s3\.(.*?)\.amazonaws\.com$`) +var amazonS3HostDot = regexp.MustCompile(`^s3.(.*?).amazonaws.com$`) // amazonS3ChinaHost - regular expression used to determine if the arg is s3 china host. -var amazonS3ChinaHost = regexp.MustCompile(`^s3\.(cn.*?)\.amazonaws\.com\.cn$`) +var amazonS3ChinaHost = regexp.MustCompile(`^s3.(cn.*?).amazonaws.com.cn$`) + +// Regular expression used to determine if the arg is elb host. +var elbAmazonRegex = regexp.MustCompile(`elb(.*?).amazonaws.com$`) + +// Regular expression used to determine if the arg is elb host in china. +var elbAmazonCnRegex = regexp.MustCompile(`elb(.*?).amazonaws.com.cn$`) // GetRegionFromURL - returns a region from url host. func GetRegionFromURL(endpointURL url.URL) string { @@ -106,6 +112,10 @@ func GetRegionFromURL(endpointURL url.URL) string { if IsAmazonGovCloudEndpoint(endpointURL) { return "us-gov-west-1" } + // if elb's are used we cannot calculate which region it may be, just return empty. + if elbAmazonRegex.MatchString(endpointURL.Host) || elbAmazonCnRegex.MatchString(endpointURL.Host) { + return "" + } parts := amazonS3HostDualStack.FindStringSubmatch(endpointURL.Host) if len(parts) > 1 { return parts[1] @@ -219,6 +229,31 @@ func QueryEncode(v url.Values) string { return buf.String() } +// TagEncode - encodes tag values in their URL encoded form. In +// addition to the percent encoding performed by urlEncodePath() used +// here, it also percent encodes '/' (forward slash) +func TagEncode(tags map[string]string) string { + if tags == nil { + return "" + } + var buf bytes.Buffer + keys := make([]string, 0, len(tags)) + for k := range tags { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := tags[k] + prefix := percentEncodeSlash(EncodePath(k)) + "=" + if buf.Len() > 0 { + buf.WriteByte('&') + } + buf.WriteString(prefix) + buf.WriteString(percentEncodeSlash(EncodePath(v))) + } + return buf.String() +} + // if object matches reserved string, no need to encode them var reservedObjectNames = regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$") @@ -274,10 +309,10 @@ func checkBucketNameCommon(bucketName string, strict bool) (err error) { return errors.New("Bucket name cannot be empty") } if len(bucketName) < 3 { - return errors.New("Bucket name cannot be smaller than 3 characters") + return errors.New("Bucket name cannot be shorter than 3 characters") } if len(bucketName) > 63 { - return errors.New("Bucket name cannot be greater than 63 characters") + return errors.New("Bucket name cannot be longer than 63 characters") } if ipAddress.MatchString(bucketName) { return errors.New("Bucket name cannot be an ip address") @@ -313,7 +348,7 @@ func CheckValidBucketNameStrict(bucketName string) (err error) { // - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html func CheckValidObjectNamePrefix(objectName string) error { if len(objectName) > 1024 { - return errors.New("Object name cannot be greater than 1024 characters") + return errors.New("Object name cannot be longer than 1024 characters") } if !utf8.ValidString(objectName) { return errors.New("Object name with non UTF-8 strings are not supported") diff --git a/vendor/github.com/minio/minio-go/v6/post-policy.go b/vendor/github.com/minio/minio-go/v6/post-policy.go index f9250b2a89d..8b0bf092df3 100644 --- a/vendor/github.com/minio/minio-go/v6/post-policy.go +++ b/vendor/github.com/minio/minio-go/v6/post-policy.go @@ -131,6 +131,27 @@ func (p *PostPolicy) SetBucket(bucketName string) error { return nil } +// SetCondition - Sets condition for credentials, date and algorithm +func (p *PostPolicy) SetCondition(matchType, condition, value string) error { + if strings.TrimSpace(value) == "" || value == "" { + return ErrInvalidArgument("No value specified for condition") + } + + policyCond := policyCondition{ + matchType: matchType, + condition: "$" + condition, + value: value, + } + if condition == "X-Amz-Credential" || condition == "X-Amz-Date" || condition == "X-Amz-Algorithm" { + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData[condition] = value + return nil + } + return ErrInvalidArgument("Invalid condition in policy") +} + // SetContentType - Sets content-type of the object for this policy // based upload. func (p *PostPolicy) SetContentType(contentType string) error { diff --git a/vendor/github.com/minio/minio-go/v6/retry.go b/vendor/github.com/minio/minio-go/v6/retry.go index 2c608bab540..f9c1095c052 100644 --- a/vendor/github.com/minio/minio-go/v6/retry.go +++ b/vendor/github.com/minio/minio-go/v6/retry.go @@ -18,10 +18,7 @@ package minio import ( - "net" "net/http" - "net/url" - "strings" "time" ) @@ -85,40 +82,6 @@ func (c Client) newRetryTimer(maxRetry int, unit time.Duration, cap time.Duratio return attemptCh } -// isHTTPReqErrorRetryable - is http requests error retryable, such -// as i/o timeout, connection broken etc.. -func isHTTPReqErrorRetryable(err error) bool { - if err == nil { - return false - } - switch e := err.(type) { - case *url.Error: - switch e.Err.(type) { - case *net.DNSError, *net.OpError, net.UnknownNetworkError: - return true - } - if strings.Contains(err.Error(), "Connection closed by foreign host") { - return true - } else if strings.Contains(err.Error(), "net/http: TLS handshake timeout") { - // If error is - tlsHandshakeTimeoutError, retry. - return true - } else if strings.Contains(err.Error(), "i/o timeout") { - // If error is - tcp timeoutError, retry. - return true - } else if strings.Contains(err.Error(), "connection timed out") { - // If err is a net.Dial timeout, retry. - return true - } else if strings.Contains(err.Error(), "net/http: HTTP/1.x transport connection broken") { - // If error is transport connection broken, retry. - return true - } else if strings.Contains(err.Error(), "net/http: timeout awaiting response headers") { - // Retry errors due to server not sending the response before timeout - return true - } - } - return false -} - // List of AWS S3 error codes which are retryable. var retryableS3Codes = map[string]struct{}{ "RequestError": {}, diff --git a/vendor/github.com/minio/minio-go/v6/s3-endpoints.go b/vendor/github.com/minio/minio-go/v6/s3-endpoints.go index 989f58c7ecb..4a8879fd53e 100644 --- a/vendor/github.com/minio/minio-go/v6/s3-endpoints.go +++ b/vendor/github.com/minio/minio-go/v6/s3-endpoints.go @@ -35,6 +35,8 @@ var awsS3EndpointMap = map[string]string{ "ap-southeast-2": "s3.dualstack.ap-southeast-2.amazonaws.com", "ap-northeast-1": "s3.dualstack.ap-northeast-1.amazonaws.com", "ap-northeast-2": "s3.dualstack.ap-northeast-2.amazonaws.com", + "ap-northeast-3": "s3.dualstack.ap-northeast-3.amazonaws.com", + "me-south-1": "s3.dualstack.me-south-1.amazonaws.com", "sa-east-1": "s3.dualstack.sa-east-1.amazonaws.com", "us-gov-west-1": "s3.dualstack.us-gov-west-1.amazonaws.com", "us-gov-east-1": "s3.dualstack.us-gov-east-1.amazonaws.com", diff --git a/vendor/github.com/minio/minio-go/v6/transport.go b/vendor/github.com/minio/minio-go/v6/transport.go index 34efa89802a..00ee4dad678 100644 --- a/vendor/github.com/minio/minio-go/v6/transport.go +++ b/vendor/github.com/minio/minio-go/v6/transport.go @@ -21,12 +21,9 @@ package minio import ( "crypto/tls" - "crypto/x509" "net" "net/http" "time" - - "golang.org/x/net/http2" ) // DefaultTransport - this default transport is similar to @@ -54,29 +51,12 @@ var DefaultTransport = func(secure bool) (http.RoundTripper, error) { } if secure { - rootCAs, _ := x509.SystemCertPool() - if rootCAs == nil { - // In some systems (like Windows) system cert pool is - // not supported or no certificates are present on the - // system - so we create a new cert pool. - rootCAs = x509.NewCertPool() - } - - // Keep TLS config. - tlsConfig := &tls.Config{ - RootCAs: rootCAs, + tr.TLSClientConfig = &tls.Config{ // Can't use SSLv3 because of POODLE and BEAST // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher // Can't use TLSv1.1 because of RC4 cipher usage MinVersion: tls.VersionTLS12, } - tr.TLSClientConfig = tlsConfig - - // Because we create a custom TLSClientConfig, we have to opt-in to HTTP/2. - // See https://github.com/golang/go/issues/14275 - if err := http2.ConfigureTransport(tr); err != nil { - return nil, err - } } return tr, nil } diff --git a/vendor/github.com/minio/minio-go/v6/utils.go b/vendor/github.com/minio/minio-go/v6/utils.go index d24cfb5c760..5b324547df8 100644 --- a/vendor/github.com/minio/minio-go/v6/utils.go +++ b/vendor/github.com/minio/minio-go/v6/utils.go @@ -36,6 +36,11 @@ import ( "github.com/minio/minio-go/v6/pkg/s3utils" ) +func trimEtag(etag string) string { + etag = strings.TrimPrefix(etag, "\"") + return strings.TrimSuffix(etag, "\"") +} + // xmlDecoder provide decoded value in xml. func xmlDecoder(body io.Reader, v interface{}) error { d := xml.NewDecoder(body) diff --git a/vendor/github.com/prometheus/alertmanager/api/v1/api.go b/vendor/github.com/prometheus/alertmanager/api/v1/api.go index fe85013a8b1..25c18a57e04 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v1/api.go +++ b/vendor/github.com/prometheus/alertmanager/api/v1/api.go @@ -29,13 +29,12 @@ import ( "github.com/prometheus/common/model" "github.com/prometheus/common/route" "github.com/prometheus/common/version" - "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/alertmanager/api/metrics" "github.com/prometheus/alertmanager/cluster" "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/dispatch" - "github.com/prometheus/alertmanager/pkg/parse" + "github.com/prometheus/alertmanager/pkg/labels" "github.com/prometheus/alertmanager/provider" "github.com/prometheus/alertmanager/silence" "github.com/prometheus/alertmanager/silence/silencepb" @@ -258,7 +257,7 @@ func (api *API) listAlerts(w http.ResponseWriter, r *http.Request) { } if filter := r.FormValue("filter"); filter != "" { - matchers, err = parse.Matchers(filter) + matchers, err = labels.ParseMatchers(filter) if err != nil { api.respondError(w, apiError{ typ: errorBadData, @@ -579,7 +578,7 @@ func (api *API) listSilences(w http.ResponseWriter, r *http.Request) { matchers := []*labels.Matcher{} if filter := r.FormValue("filter"); filter != "" { - matchers, err = parse.Matchers(filter) + matchers, err = labels.ParseMatchers(filter) if err != nil { api.respondError(w, apiError{ typ: errorBadData, @@ -792,6 +791,7 @@ func (api *API) receive(r *http.Request, v interface{}) error { err := dec.Decode(v) if err != nil { level.Debug(api.logger).Log("msg", "Decoding request failed", "err", err) + return err } - return err + return nil } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/api.go b/vendor/github.com/prometheus/alertmanager/api/v2/api.go index 353a132e94c..c147a23a6f4 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/api.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/api.go @@ -29,7 +29,6 @@ import ( "github.com/prometheus/client_golang/prometheus" prometheus_model "github.com/prometheus/common/model" "github.com/prometheus/common/version" - "github.com/prometheus/prometheus/pkg/labels" "github.com/rs/cors" "github.com/prometheus/alertmanager/api/metrics" @@ -44,7 +43,7 @@ import ( "github.com/prometheus/alertmanager/cluster" "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/dispatch" - "github.com/prometheus/alertmanager/pkg/parse" + "github.com/prometheus/alertmanager/pkg/labels" "github.com/prometheus/alertmanager/provider" "github.com/prometheus/alertmanager/silence" "github.com/prometheus/alertmanager/silence/silencepb" @@ -557,7 +556,7 @@ func (api *API) getSilencesHandler(params silence_ops.GetSilencesParams) middlew matchers := []*labels.Matcher{} if params.Filter != nil { for _, matcherString := range params.Filter { - matcher, err := parse.Matcher(matcherString) + matcher, err := labels.ParseMatcher(matcherString) if err != nil { level.Error(api.logger).Log("msg", "failed to parse matchers", "err", err) return alert_ops.NewGetAlertsBadRequest().WithPayload(err.Error()) @@ -638,8 +637,6 @@ func gettableSilenceMatchesFilterLabels(s open_api_models.GettableSilence, match return matchFilterLabels(matchers, sms) } -// func matchesFilterLabels(labels model.LabelSet, matchers []*labels.Matcher) bool { - func (api *API) getSilenceHandler(params silence_ops.GetSilenceParams) middleware.Responder { sils, _, err := api.silences.Query(silence.QIDs(params.SilenceID.String())) if err != nil { @@ -776,7 +773,7 @@ func postableSilenceToProto(s *open_api_models.PostableSilence) (*silencepb.Sile func parseFilter(filter []string) ([]*labels.Matcher, error) { matchers := make([]*labels.Matcher, 0, len(filter)) for _, matcherString := range filter { - matcher, err := parse.Matcher(matcherString) + matcher, err := labels.ParseMatcher(matcherString) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/configure_alertmanager.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/configure_alertmanager.go index 8cfe1fc6b82..5ed19b271ec 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/configure_alertmanager.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/configure_alertmanager.go @@ -52,33 +52,51 @@ func configureAPI(api *operations.AlertmanagerAPI) http.Handler { api.JSONProducer = runtime.JSONProducer() - api.SilenceDeleteSilenceHandler = silence.DeleteSilenceHandlerFunc(func(params silence.DeleteSilenceParams) middleware.Responder { - return middleware.NotImplemented("operation silence.DeleteSilence has not yet been implemented") - }) - api.AlertgroupGetAlertGroupsHandler = alertgroup.GetAlertGroupsHandlerFunc(func(params alertgroup.GetAlertGroupsParams) middleware.Responder { - return middleware.NotImplemented("operation alertgroup.GetAlertGroups has not yet been implemented") - }) - api.AlertGetAlertsHandler = alert.GetAlertsHandlerFunc(func(params alert.GetAlertsParams) middleware.Responder { - return middleware.NotImplemented("operation alert.GetAlerts has not yet been implemented") - }) - api.ReceiverGetReceiversHandler = receiver.GetReceiversHandlerFunc(func(params receiver.GetReceiversParams) middleware.Responder { - return middleware.NotImplemented("operation receiver.GetReceivers has not yet been implemented") - }) - api.SilenceGetSilenceHandler = silence.GetSilenceHandlerFunc(func(params silence.GetSilenceParams) middleware.Responder { - return middleware.NotImplemented("operation silence.GetSilence has not yet been implemented") - }) - api.SilenceGetSilencesHandler = silence.GetSilencesHandlerFunc(func(params silence.GetSilencesParams) middleware.Responder { - return middleware.NotImplemented("operation silence.GetSilences has not yet been implemented") - }) - api.GeneralGetStatusHandler = general.GetStatusHandlerFunc(func(params general.GetStatusParams) middleware.Responder { - return middleware.NotImplemented("operation general.GetStatus has not yet been implemented") - }) - api.AlertPostAlertsHandler = alert.PostAlertsHandlerFunc(func(params alert.PostAlertsParams) middleware.Responder { - return middleware.NotImplemented("operation alert.PostAlerts has not yet been implemented") - }) - api.SilencePostSilencesHandler = silence.PostSilencesHandlerFunc(func(params silence.PostSilencesParams) middleware.Responder { - return middleware.NotImplemented("operation silence.PostSilences has not yet been implemented") - }) + if api.SilenceDeleteSilenceHandler == nil { + api.SilenceDeleteSilenceHandler = silence.DeleteSilenceHandlerFunc(func(params silence.DeleteSilenceParams) middleware.Responder { + return middleware.NotImplemented("operation silence.DeleteSilence has not yet been implemented") + }) + } + if api.AlertgroupGetAlertGroupsHandler == nil { + api.AlertgroupGetAlertGroupsHandler = alertgroup.GetAlertGroupsHandlerFunc(func(params alertgroup.GetAlertGroupsParams) middleware.Responder { + return middleware.NotImplemented("operation alertgroup.GetAlertGroups has not yet been implemented") + }) + } + if api.AlertGetAlertsHandler == nil { + api.AlertGetAlertsHandler = alert.GetAlertsHandlerFunc(func(params alert.GetAlertsParams) middleware.Responder { + return middleware.NotImplemented("operation alert.GetAlerts has not yet been implemented") + }) + } + if api.ReceiverGetReceiversHandler == nil { + api.ReceiverGetReceiversHandler = receiver.GetReceiversHandlerFunc(func(params receiver.GetReceiversParams) middleware.Responder { + return middleware.NotImplemented("operation receiver.GetReceivers has not yet been implemented") + }) + } + if api.SilenceGetSilenceHandler == nil { + api.SilenceGetSilenceHandler = silence.GetSilenceHandlerFunc(func(params silence.GetSilenceParams) middleware.Responder { + return middleware.NotImplemented("operation silence.GetSilence has not yet been implemented") + }) + } + if api.SilenceGetSilencesHandler == nil { + api.SilenceGetSilencesHandler = silence.GetSilencesHandlerFunc(func(params silence.GetSilencesParams) middleware.Responder { + return middleware.NotImplemented("operation silence.GetSilences has not yet been implemented") + }) + } + if api.GeneralGetStatusHandler == nil { + api.GeneralGetStatusHandler = general.GetStatusHandlerFunc(func(params general.GetStatusParams) middleware.Responder { + return middleware.NotImplemented("operation general.GetStatus has not yet been implemented") + }) + } + if api.AlertPostAlertsHandler == nil { + api.AlertPostAlertsHandler = alert.PostAlertsHandlerFunc(func(params alert.PostAlertsParams) middleware.Responder { + return middleware.NotImplemented("operation alert.PostAlerts has not yet been implemented") + }) + } + if api.SilencePostSilencesHandler == nil { + api.SilencePostSilencesHandler = silence.PostSilencesHandlerFunc(func(params silence.PostSilencesParams) middleware.Responder { + return middleware.NotImplemented("operation silence.PostSilences has not yet been implemented") + }) + } api.ServerShutdown = func() {} diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/get_alerts_responses.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/get_alerts_responses.go index a9a4bd8852c..ed528226357 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/get_alerts_responses.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/get_alerts_responses.go @@ -65,13 +65,13 @@ func (o *GetAlertsOK) WriteResponse(rw http.ResponseWriter, producer runtime.Pro rw.WriteHeader(200) payload := o.Payload if payload == nil { - payload = make(models.GettableAlerts, 0, 50) + // return empty array + payload = models.GettableAlerts{} } if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } // GetAlertsBadRequestCode is the HTTP code returned for type GetAlertsBadRequest @@ -114,7 +114,6 @@ func (o *GetAlertsBadRequest) WriteResponse(rw http.ResponseWriter, producer run if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } // GetAlertsInternalServerErrorCode is the HTTP code returned for type GetAlertsInternalServerError @@ -157,5 +156,4 @@ func (o *GetAlertsInternalServerError) WriteResponse(rw http.ResponseWriter, pro if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/get_alerts_urlbuilder.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/get_alerts_urlbuilder.go index 43047083906..a2f41d24d63 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/get_alerts_urlbuilder.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/get_alerts_urlbuilder.go @@ -67,12 +67,12 @@ func (o *GetAlertsURL) Build() (*url.URL, error) { qs := make(url.Values) - var active string + var activeQ string if o.Active != nil { - active = swag.FormatBool(*o.Active) + activeQ = swag.FormatBool(*o.Active) } - if active != "" { - qs.Set("active", active) + if activeQ != "" { + qs.Set("active", activeQ) } var filterIR []string @@ -89,36 +89,36 @@ func (o *GetAlertsURL) Build() (*url.URL, error) { qs.Add("filter", qsv) } - var inhibited string + var inhibitedQ string if o.Inhibited != nil { - inhibited = swag.FormatBool(*o.Inhibited) + inhibitedQ = swag.FormatBool(*o.Inhibited) } - if inhibited != "" { - qs.Set("inhibited", inhibited) + if inhibitedQ != "" { + qs.Set("inhibited", inhibitedQ) } - var receiver string + var receiverQ string if o.Receiver != nil { - receiver = *o.Receiver + receiverQ = *o.Receiver } - if receiver != "" { - qs.Set("receiver", receiver) + if receiverQ != "" { + qs.Set("receiver", receiverQ) } - var silenced string + var silencedQ string if o.Silenced != nil { - silenced = swag.FormatBool(*o.Silenced) + silencedQ = swag.FormatBool(*o.Silenced) } - if silenced != "" { - qs.Set("silenced", silenced) + if silencedQ != "" { + qs.Set("silenced", silencedQ) } - var unprocessed string + var unprocessedQ string if o.Unprocessed != nil { - unprocessed = swag.FormatBool(*o.Unprocessed) + unprocessedQ = swag.FormatBool(*o.Unprocessed) } - if unprocessed != "" { - qs.Set("unprocessed", unprocessed) + if unprocessedQ != "" { + qs.Set("unprocessed", unprocessedQ) } _result.RawQuery = qs.Encode() diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/post_alerts_responses.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/post_alerts_responses.go index 5fc53cd8408..7e273c31067 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/post_alerts_responses.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alert/post_alerts_responses.go @@ -89,7 +89,6 @@ func (o *PostAlertsBadRequest) WriteResponse(rw http.ResponseWriter, producer ru if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } // PostAlertsInternalServerErrorCode is the HTTP code returned for type PostAlertsInternalServerError @@ -132,5 +131,4 @@ func (o *PostAlertsInternalServerError) WriteResponse(rw http.ResponseWriter, pr if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup/get_alert_groups_responses.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup/get_alert_groups_responses.go index 1218c1295b3..bd959cb3a30 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup/get_alert_groups_responses.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup/get_alert_groups_responses.go @@ -65,13 +65,13 @@ func (o *GetAlertGroupsOK) WriteResponse(rw http.ResponseWriter, producer runtim rw.WriteHeader(200) payload := o.Payload if payload == nil { - payload = make(models.AlertGroups, 0, 50) + // return empty array + payload = models.AlertGroups{} } if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } // GetAlertGroupsBadRequestCode is the HTTP code returned for type GetAlertGroupsBadRequest @@ -114,7 +114,6 @@ func (o *GetAlertGroupsBadRequest) WriteResponse(rw http.ResponseWriter, produce if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } // GetAlertGroupsInternalServerErrorCode is the HTTP code returned for type GetAlertGroupsInternalServerError @@ -157,5 +156,4 @@ func (o *GetAlertGroupsInternalServerError) WriteResponse(rw http.ResponseWriter if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup/get_alert_groups_urlbuilder.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup/get_alert_groups_urlbuilder.go index 919547b3af3..cf95a2e1025 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup/get_alert_groups_urlbuilder.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup/get_alert_groups_urlbuilder.go @@ -66,12 +66,12 @@ func (o *GetAlertGroupsURL) Build() (*url.URL, error) { qs := make(url.Values) - var active string + var activeQ string if o.Active != nil { - active = swag.FormatBool(*o.Active) + activeQ = swag.FormatBool(*o.Active) } - if active != "" { - qs.Set("active", active) + if activeQ != "" { + qs.Set("active", activeQ) } var filterIR []string @@ -88,28 +88,28 @@ func (o *GetAlertGroupsURL) Build() (*url.URL, error) { qs.Add("filter", qsv) } - var inhibited string + var inhibitedQ string if o.Inhibited != nil { - inhibited = swag.FormatBool(*o.Inhibited) + inhibitedQ = swag.FormatBool(*o.Inhibited) } - if inhibited != "" { - qs.Set("inhibited", inhibited) + if inhibitedQ != "" { + qs.Set("inhibited", inhibitedQ) } - var receiver string + var receiverQ string if o.Receiver != nil { - receiver = *o.Receiver + receiverQ = *o.Receiver } - if receiver != "" { - qs.Set("receiver", receiver) + if receiverQ != "" { + qs.Set("receiver", receiverQ) } - var silenced string + var silencedQ string if o.Silenced != nil { - silenced = swag.FormatBool(*o.Silenced) + silencedQ = swag.FormatBool(*o.Silenced) } - if silenced != "" { - qs.Set("silenced", silenced) + if silencedQ != "" { + qs.Set("silenced", silencedQ) } _result.RawQuery = qs.Encode() diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertmanager_api.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertmanager_api.go index 8f57c7a6de6..c04bfe754ec 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertmanager_api.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/alertmanager_api.go @@ -100,13 +100,13 @@ type AlertmanagerAPI struct { Middleware func(middleware.Builder) http.Handler // BasicAuthenticator generates a runtime.Authenticator from the supplied basic auth function. - // It has a default implemention in the security package, however you can replace it for your particular usage. + // It has a default implementation in the security package, however you can replace it for your particular usage. BasicAuthenticator func(security.UserPassAuthentication) runtime.Authenticator // APIKeyAuthenticator generates a runtime.Authenticator from the supplied token auth function. - // It has a default implemention in the security package, however you can replace it for your particular usage. + // It has a default implementation in the security package, however you can replace it for your particular usage. APIKeyAuthenticator func(string, string, security.TokenAuthentication) runtime.Authenticator // BearerAuthenticator generates a runtime.Authenticator from the supplied bearer token auth function. - // It has a default implemention in the security package, however you can replace it for your particular usage. + // It has a default implementation in the security package, however you can replace it for your particular usage. BearerAuthenticator func(string, security.ScopedTokenAuthentication) runtime.Authenticator // JSONConsumer registers a consumer for a "application/json" mime type diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver/get_receivers_responses.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver/get_receivers_responses.go index dbfccc0bda5..e39c91e6b7e 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver/get_receivers_responses.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver/get_receivers_responses.go @@ -65,11 +65,11 @@ func (o *GetReceiversOK) WriteResponse(rw http.ResponseWriter, producer runtime. rw.WriteHeader(200) payload := o.Payload if payload == nil { + // return empty array payload = make([]*models.Receiver, 0, 50) } if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/delete_silence_responses.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/delete_silence_responses.go index 9c1e9355534..de87e29a3b8 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/delete_silence_responses.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/delete_silence_responses.go @@ -89,5 +89,4 @@ func (o *DeleteSilenceInternalServerError) WriteResponse(rw http.ResponseWriter, if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/delete_silence_urlbuilder.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/delete_silence_urlbuilder.go index e98d616a681..a9ca5b6b08b 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/delete_silence_urlbuilder.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/delete_silence_urlbuilder.go @@ -62,7 +62,7 @@ func (o *DeleteSilenceURL) Build() (*url.URL, error) { if silenceID != "" { _path = strings.Replace(_path, "{silenceID}", silenceID, -1) } else { - return nil, errors.New("SilenceID is required on DeleteSilenceURL") + return nil, errors.New("silenceId is required on DeleteSilenceURL") } _basePath := o._basePath diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silence_responses.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silence_responses.go index c05a317d7cc..d2e32940270 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silence_responses.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silence_responses.go @@ -135,5 +135,4 @@ func (o *GetSilenceInternalServerError) WriteResponse(rw http.ResponseWriter, pr if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silence_urlbuilder.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silence_urlbuilder.go index 0d2efa769b0..5080a74ddee 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silence_urlbuilder.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silence_urlbuilder.go @@ -62,7 +62,7 @@ func (o *GetSilenceURL) Build() (*url.URL, error) { if silenceID != "" { _path = strings.Replace(_path, "{silenceID}", silenceID, -1) } else { - return nil, errors.New("SilenceID is required on GetSilenceURL") + return nil, errors.New("silenceId is required on GetSilenceURL") } _basePath := o._basePath diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silences_responses.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silences_responses.go index f4238a00313..c0940ce61bc 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silences_responses.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/get_silences_responses.go @@ -65,13 +65,13 @@ func (o *GetSilencesOK) WriteResponse(rw http.ResponseWriter, producer runtime.P rw.WriteHeader(200) payload := o.Payload if payload == nil { - payload = make(models.GettableSilences, 0, 50) + // return empty array + payload = models.GettableSilences{} } if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } // GetSilencesInternalServerErrorCode is the HTTP code returned for type GetSilencesInternalServerError @@ -114,5 +114,4 @@ func (o *GetSilencesInternalServerError) WriteResponse(rw http.ResponseWriter, p if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/post_silences_responses.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/post_silences_responses.go index 354a3663e24..7570855d271 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/post_silences_responses.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/post_silences_responses.go @@ -109,7 +109,6 @@ func (o *PostSilencesBadRequest) WriteResponse(rw http.ResponseWriter, producer if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } // PostSilencesNotFoundCode is the HTTP code returned for type PostSilencesNotFound @@ -152,5 +151,4 @@ func (o *PostSilencesNotFound) WriteResponse(rw http.ResponseWriter, producer ru if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } - } diff --git a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/server.go b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/server.go index a17ca5c4e39..fb929476583 100644 --- a/vendor/github.com/prometheus/alertmanager/api/v2/restapi/server.go +++ b/vendor/github.com/prometheus/alertmanager/api/v2/restapi/server.go @@ -101,7 +101,7 @@ type Server struct { TLSHost string `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"` TLSPort int `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"` TLSCertificate flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"` - TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure conections" env:"TLS_PRIVATE_KEY"` + TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"` TLSCACertificate flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"` TLSListenLimit int `long:"tls-listen-limit" description:"limit the number of outstanding requests"` TLSKeepAlive time.Duration `long:"tls-keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)"` @@ -147,7 +147,6 @@ func (s *Server) SetAPI(api *operations.AlertmanagerAPI) { } s.api = api - s.api.Logger = log.Printf s.handler = configureAPI(api) } @@ -266,7 +265,7 @@ func (s *Server) Serve() (err error) { // https://github.com/golang/go/tree/master/src/crypto/elliptic CurvePreferences: []tls.CurveID{tls.CurveP256}, // Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility - NextProtos: []string{"http/1.1", "h2"}, + NextProtos: []string{"h2", "http/1.1"}, // https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols MinVersion: tls.VersionTLS12, // These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy @@ -307,7 +306,7 @@ func (s *Server) Serve() (err error) { // call custom TLS configurator configureTLS(httpsServer.TLSConfig) - if len(httpsServer.TLSConfig.Certificates) == 0 { + if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil { // after standard and custom config are passed, this ends up with no certificate if s.TLSCertificate == "" { if s.TLSCertificateKey == "" { diff --git a/vendor/github.com/prometheus/alertmanager/asset/assets_vfsdata.go b/vendor/github.com/prometheus/alertmanager/asset/assets_vfsdata.go index c0ce1e2ab42..bcc6f6e7ff8 100644 --- a/vendor/github.com/prometheus/alertmanager/asset/assets_vfsdata.go +++ b/vendor/github.com/prometheus/alertmanager/asset/assets_vfsdata.go @@ -136,9 +136,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: 98803, + uncompressedSize: 98980, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\xfd\x09\x7b\xdb\xbc\xb2\x20\x0c\xfe\x15\x9b\xad\xab\x03\x44\x65\x46\xf2\x96\x84\x32\x8e\xc6\x49\xec\xec\x76\xe2\xec\xf1\xeb\xce\x07\x52\x90\x4d\x4b\x06\x15\x08\xf4\x12\x8b\xfd\xdb\xe7\x41\x81\xab\x44\x2a\x39\xdd\xb7\x67\xbe\x7b\xdf\x13\x8b\x04\x50\x28\x00\x85\xda\x50\x28\xae\x8f\x62\x19\xe8\x30\x92\x44\xd2\x7b\x27\x9e\x89\xb5\x99\x56\x61\xa0\x9d\x7e\x56\xb0\xa6\x88\x04\x05\x9a\xde\x2b\xa1\x63\x25\xd7\xb4\xcb\x99\x04\xed\x8e\x98\x02\x9d\xe4\xd5\x66\xa4\xa8\xa2\xc8\x26\x68\xc8\x41\xab\xbc\xa0\xdc\x5b\x06\x8e\x28\x90\x34\x49\x68\x01\x4a\x10\x51\x02\xb5\x05\xa2\x00\xa5\x97\x41\xad\x84\x2e\x88\x06\x0b\xbf\xdc\x81\x26\x71\xa9\x83\x6d\x88\x8b\x0e\xc4\x32\xb4\xff\xb4\xcf\x98\x08\xc8\x7b\x2d\x77\x1b\x12\x5e\xea\x76\x07\x78\xd1\x6d\xbc\x0c\xf0\xbf\x01\x13\x4e\x62\x28\xe3\x52\x46\x26\x26\x41\x09\x99\x5d\x08\x0a\x64\xf8\x32\xcc\xff\x3b\xf8\x05\x84\xc3\x02\x86\x65\x14\x39\x09\x4b\x28\x3e\x82\xb0\x40\x31\x58\x06\xfb\xff\x33\xac\x43\x12\xc0\x32\xde\x65\xc4\x03\x12\x95\x10\x7f\x0c\x51\x81\x78\xb8\x0c\xf9\xff\x9f\x63\x89\x48\x08\xb5\xa3\x29\x0f\x27\x22\xa3\xd2\x70\x9e\xc0\xa8\x18\x4e\xb4\x0c\xfc\xff\x65\x23\x1c\x91\x08\x9a\xc6\x58\x1e\xe4\x78\x81\xcd\x6d\x32\xc6\xa4\xcb\x07\xd2\x1d\x11\xf3\xde\x33\xfd\x10\x5d\x6a\x71\x6b\x5b\x40\x81\xe4\x56\xb5\x0d\x88\xbc\x15\x11\xa5\x86\xfb\x59\x43\x28\x86\xbc\xbd\xd8\x14\xe2\x72\x63\x12\x97\xda\xdf\x14\xed\xa1\x98\xc7\x9d\x65\x08\xc0\x17\x60\x10\x5e\x02\x33\x29\x83\x81\x62\x8d\x76\xeb\x00\x41\xb0\x0c\x8a\x04\x25\x68\x7e\x15\x1a\x14\x64\xf0\xa8\x1e\x1e\x84\xb5\x10\x49\x48\x93\x6b\xae\xd6\x46\x4c\x90\x62\x39\xed\xd2\x8c\x22\x45\x4c\x99\x60\xfb\x4a\xf1\x3b\x22\x29\xc4\xac\xdb\x8f\xf7\x64\x3f\xee\x74\xa8\x38\x8d\xcf\x98\x26\xaa\x13\xd3\x7e\xc6\xff\x13\x0a\xd7\x6c\x56\x81\x54\xc0\xd1\x05\x1c\xc1\xba\x7d\xb1\x27\xdb\x6d\xe5\xfa\x7d\xd1\xe9\x50\x7d\x2a\xce\x98\x72\x39\x28\x66\x5e\xe5\xc2\x6f\x22\xe4\xb9\xbe\x60\x02\x8e\x8d\x68\xa1\x09\x85\x21\x23\x8b\x1d\x64\x9b\xe5\x54\x9e\x25\x14\x56\x0d\x24\x03\x08\x71\x8a\x8b\xa0\xc0\x59\xb7\xcf\xf7\x44\x9f\x77\x3a\x34\x3e\xe5\x67\x4c\x9f\xf2\xb3\x0c\x83\xf8\x54\x9e\x31\x05\x71\x42\xa1\x79\x58\x2a\x83\x9a\xcd\x94\xee\xf4\xb2\xb9\xd2\xc5\x5c\xa9\xd3\x38\x87\x2b\x4e\xf5\x19\x93\x20\xfe\x1e\x5f\x03\x4c\x20\x30\xc5\xcc\xee\xd1\xa7\xf1\x19\xa8\x7c\xea\xd5\x5f\x42\xda\xe8\xf5\xbb\x7b\x4c\xf4\xc5\xc6\x46\x0e\x48\x2c\x00\xa2\xd0\x5a\x9e\xe4\x55\xc3\xad\x19\xac\x24\x66\xb8\x15\xca\xf8\x3f\x5e\x18\x64\x1a\x1d\x0e\x66\x81\x72\xc8\x71\x2d\xe4\x9c\x80\x66\x93\x30\x10\x38\x82\xda\x7a\xb6\x77\x55\xf4\x2e\x37\x44\x3f\x43\x66\x2f\x6e\xb7\x49\x9c\xe3\x46\xfb\x19\xbe\x3c\x43\xb2\x13\x53\x08\x58\xb7\x1f\xec\x89\x7e\xd0\xe9\x50\x7e\x1a\x98\x75\x0e\xce\xb0\xaa\x2d\x89\xb3\x92\x8e\x30\xb4\x15\xe4\x34\xc0\x13\x0a\xf7\x2d\xaf\x9b\xd0\x42\xfd\xbb\x2a\x53\xf4\x7d\xcb\xeb\x01\xf7\x24\xf8\x9e\x4a\x70\x9b\x5e\xb0\x19\xb9\x2a\x55\x3f\x30\xac\x37\xc3\x4a\xb1\x16\x68\x26\x53\x6c\xfb\x7a\x63\xa3\x4f\x15\xbb\x22\xf2\x54\x57\x17\x38\x6f\x3e\xad\x36\x3f\x3d\xeb\x4b\xd7\xef\x4b\x26\x5d\x9f\x2a\x77\x1a\xcf\x2e\x88\x74\x79\xa9\xa5\xa9\x77\xbe\x92\x55\x9c\x9e\xf5\x95\xeb\xb7\xdb\xda\xec\x62\xb3\x97\x41\x33\xed\xfa\x54\x58\x70\xb8\x84\x2e\x07\xed\x72\x9a\xc3\x3d\x30\xfc\x9a\xc2\x1d\x23\x7a\x01\xb2\xe1\xf6\x19\xec\xb8\x0c\xbb\xdd\x16\xd5\x0e\x40\x30\xe1\xfa\x34\xb6\xdd\xdc\x16\xdd\x80\xa8\x76\x15\x9b\xae\xc2\xa5\x7e\x8c\x70\x28\x96\x77\xb1\xa7\x76\x3b\xae\xeb\x0e\x62\x16\xbb\x3e\xe5\xb6\xd3\xfd\x6a\xa7\x10\x57\x3b\xe6\xa6\xe3\xb8\xa6\x63\x23\x55\xb2\xae\x83\xfa\xae\xdb\x6d\xde\xdc\x3f\x70\xc6\x5d\x9f\x06\x16\x8b\x9b\x65\x2c\x80\x57\x31\x09\x68\x95\x9d\x69\x28\x04\xf8\x01\x31\x44\xe1\xce\x22\xa5\xeb\xb9\xec\x2b\xa2\x0d\x07\xd7\x44\x51\x9a\xe0\x7f\xfd\x12\x28\xf1\x57\xa0\x2c\x1f\x19\x9b\xda\x25\xc2\xd4\x8c\xb1\x1b\x3d\xe8\x7a\xe6\xc7\x9d\x1e\x6c\xf4\xbc\x1e\xf6\xb0\xc4\x7a\x4b\x3c\xaf\xa1\x28\x88\xe4\x2c\x9a\x08\x77\x12\x9d\x13\xd9\x71\xbc\xb5\xbd\x50\x6a\xa1\x24\x9f\xcc\xfe\xed\x50\x50\xe5\x3d\xf7\xcc\xec\x02\x7d\xa1\xa2\x9b\xb5\x03\xa5\x22\x45\x9c\x0b\xad\xa7\x33\xef\xe1\xc3\xf3\x50\x5f\xc4\xbe\x1b\x44\x57\x0f\xc5\xe4\xea\x61\x10\x29\xf1\xd0\x9f\x44\xfe\xc3\x9e\xdb\x75\xbb\x0f\x2f\x42\xa9\x67\x0f\x9d\x8e\xec\x38\xee\xd5\xd0\x29\x89\xe7\xc3\x05\x9e\x09\x66\x63\x40\xcc\x8e\x70\xd5\xbb\x20\x68\xdf\xf0\x16\xcd\x84\x3b\x8d\xa6\x84\xd2\xbe\x29\xd3\xb8\x6c\x3e\x96\x97\xf8\x5b\x0e\xf5\xa8\xd8\x14\xe1\x88\xf4\xba\xdd\x3d\x4d\x33\xfe\x6a\x17\xff\x18\xfb\xa5\xb0\xde\xed\x87\x23\x22\x19\x63\x2a\xad\x61\xdf\x38\x91\x7f\x29\x02\xed\xac\x33\x7d\x37\x15\xd1\x68\x4d\xce\xe7\x32\x9e\x4c\x8c\xce\x90\xff\xca\x9a\x38\x59\xc7\x0e\xcb\xab\xb7\xdb\xcf\xc8\x0e\x85\xf5\x5e\xce\x0b\xe3\xb5\x50\xae\x49\xb7\xb5\xd7\x6d\xb7\x89\x64\x07\x48\x1d\xca\xfc\x35\x88\x48\x1a\x8e\xc8\xfa\x11\x91\x28\xad\xcc\x3f\xba\xd3\x33\xc3\x4b\xb1\xea\xf5\x33\xf4\x90\xb7\x5c\xb2\x19\x39\xa4\xf0\x71\x49\x87\x48\x6b\x1d\xa6\x9c\xbc\x58\xbc\x57\x19\x0b\xaa\x1d\x5d\x36\x3d\x38\x13\x83\xae\x27\xf7\x14\x92\x95\x99\x8b\x75\xe9\xb6\xd2\x72\xa2\xd9\x2b\xc3\xe9\xcc\xc6\xa1\x74\xa0\xbd\xf4\x85\x0f\xca\xf5\xf1\x85\x79\x0a\x40\xb9\x81\x15\x02\x86\x4f\xa2\xf2\xd2\x6e\xaf\x57\x1b\x5b\xee\x69\xd5\x98\x82\xb2\xe7\x73\x03\x6d\xd0\xf3\x94\xeb\x1b\x04\xba\x56\xeb\x7a\xdb\x30\x4e\x3b\x2a\xba\xd7\x4d\x28\xfc\x6c\xd4\x77\xd2\x4a\xbd\xe6\x5d\xd0\xdd\x7b\x95\x89\xbe\xc6\x1a\xac\xb1\x8a\xdd\xa5\xb6\x38\x1f\xc9\x5e\x77\x70\xa7\x3d\x3d\xb8\xd5\xde\x8d\x36\xaa\xc2\x6f\xd6\x2d\x56\xe3\xb8\x22\xbe\x72\xd1\x95\x97\x3f\xad\xca\xe7\xac\x06\x04\x9e\x2e\xd5\xfa\x54\x32\x28\x64\xf1\xfa\xa4\x8c\xd6\x7d\x92\x53\xa0\x40\x0a\xb4\x2a\xa4\x3c\x15\x67\xd5\x02\x95\xea\x96\xa6\x20\x1b\x04\x4e\xfe\x73\x36\x23\x2f\x4b\x94\xf4\xd2\x82\x37\x74\x34\xd3\x2a\x94\xe7\x25\xb2\xcf\xe9\xa8\xa3\x52\xd2\xf1\xb3\x57\xaa\x6f\x11\xba\xb2\x34\x90\x12\x40\xbf\xa4\xda\x94\x84\x2a\x72\xed\xa2\x6a\x05\x9f\x5f\x4d\xc4\x20\x3b\x86\x5d\xfd\x47\x85\x7f\xa7\xac\xd9\xb9\xe4\x4c\xb9\xc1\x05\x57\xcf\xa2\xa1\xd8\xd7\x24\xa6\x7d\xbe\xb7\xb3\xb3\xf9\x64\x77\x3e\xdf\xd9\xdd\xea\x3d\xd9\xe3\x03\x92\xaa\x74\x9f\xac\x52\x47\xc1\xa8\x79\x5e\xf5\x6d\x47\x9d\xc6\x9d\x9e\x2d\x64\x9b\x34\xc9\x19\xd3\x65\x14\x4a\xe2\x38\x75\x14\x56\xa0\x79\x7a\x06\x15\x35\xcc\x6a\xbb\x39\x82\x86\x71\x04\x4b\x78\xc6\x9d\x0e\x04\x55\x5c\x83\xf9\x9c\xf0\x8e\x6d\x60\x90\x04\x83\x1e\xa7\xd4\xc8\x53\xe4\x90\x3c\xc7\x4c\x97\x30\xeb\xff\x47\x4a\x78\x86\x96\xb6\x68\xe9\xbf\x46\x4b\xe7\x68\x59\xd5\xdb\xa0\x66\xf6\x5e\x21\xcf\x90\x98\xde\xaf\xd4\xb0\x32\x74\x8c\x0a\x9f\xa2\x12\x33\x54\xe2\x79\x15\x15\x81\x2b\xb9\xbb\xb5\xd9\x9d\xcf\x77\x1e\x6d\x6d\x6f\xed\xf1\xf9\xdc\xe8\xb3\xa7\x1b\x1b\xe2\xcc\xa8\xae\x19\x16\xf1\x02\x16\xf0\xa5\x89\x16\x95\x3b\x9b\x4e\x42\xc3\xe3\x13\x0a\xaf\x9b\x6b\xe1\xd4\x62\xa5\x77\x35\x83\xa9\xd5\xce\xff\x82\x88\xad\x4e\x9b\x29\xed\x46\xad\x8d\xab\x44\xa1\xa9\xd9\x9e\x71\x75\xd4\xf1\x7c\x4e\x4c\xf5\x8d\x0d\x7d\xd6\x11\x96\x24\x04\xcd\x45\x50\x37\xc9\x64\x51\x3a\xfd\x2f\x56\x58\xb0\xff\xbd\x98\xac\x2f\xa0\xd2\x4b\x72\x9c\x28\x7c\x6e\x98\xdd\x8d\xde\x9e\x72\x43\x39\x14\xb7\xc7\x23\x3b\xc5\xdf\x9b\xd6\xa1\xcb\xd8\x42\xd5\x0f\x8d\x4c\x26\xb3\x79\xf2\x21\x1a\xf9\x36\xe1\x33\xfd\x2a\x6f\xcf\xf2\xb2\x8d\xac\x7a\x42\xe1\xeb\x12\x48\x3b\x55\xb9\x21\x12\x8e\x88\xde\xeb\x65\xfc\xb2\x55\x62\x8d\x5d\x40\xa5\x7e\xa3\xb7\x67\xa6\xa5\xc0\x14\xf5\x9f\x4c\x97\x17\x14\x44\x87\xe9\xaa\x06\x8f\x0b\xf5\x6d\x25\xc7\x84\x1f\x8d\x92\x53\x6e\xac\x50\x1d\xe5\x03\x34\x81\xdf\x34\xb7\x7e\xb8\xaa\xf5\x43\x35\xef\x62\xf1\x3b\xae\x2f\xdc\x69\x74\xd3\xac\xbe\xfe\x97\x6c\x94\xba\xea\xbf\x64\xbf\x58\x44\x26\x07\xcf\x48\xaf\x47\xbd\xee\x9e\x6e\xb7\xe5\x5e\x77\x3e\xd7\x46\xdf\xea\xee\xc9\x81\xee\x48\x4f\x5b\x2d\x1c\x7b\xe4\x9a\xcb\x4d\x3b\x3f\x52\x32\x7c\x15\x88\x70\x02\x2a\x7d\x18\x4d\xa2\x48\x81\x4e\x9f\x54\x14\xcb\x21\x88\xf4\x69\x12\x9d\x37\xca\x99\x76\x7b\xd5\xa8\xe7\xf3\x55\xa5\xeb\x8c\x65\xbc\x2d\x96\xec\x4f\xc6\x57\x46\x38\x86\xe3\x77\xf8\x1e\x8b\xb3\xe7\xd0\xd8\xd3\xed\x76\xb8\xc7\xd3\xad\x17\xb1\xb8\xbc\xe7\x14\xed\x07\x4c\x9e\x86\x9d\xce\x19\x63\x2c\x3e\x55\x9d\xce\x59\xbb\x4d\x7a\x66\x06\xa3\x01\xd1\x9d\x0e\x08\xd6\x33\x82\xab\xd3\x01\xe4\xcf\x8c\x91\xdd\xad\xed\xc7\x8f\xdb\x11\x1d\x2c\x34\xf4\x7a\x34\x67\x89\x4f\x49\x30\x50\xde\x46\x0f\x75\xef\x84\x02\x97\xcd\x4c\x4d\xed\x65\x0c\x7a\x50\xed\x42\x57\x51\xa5\x03\xb3\xf9\xb5\x3b\x8b\xfd\x99\x56\x44\xc1\x26\xa5\x74\xa0\x3a\x9b\xde\x46\xcf\xc3\xa2\x53\x75\x46\xe9\xc0\xf9\xc7\xe8\xdf\xcc\x3c\x0d\x36\x36\x3d\xd5\xe9\x99\x0a\x1b\x46\xeb\x0b\x56\xa0\xb1\xd0\x9b\xa1\xa1\x84\x42\x24\x6b\x79\x5b\x5f\xee\xe5\x8c\x4d\x76\x3a\x39\x11\x96\x61\x48\x6a\x37\xf2\xf6\x63\xc3\xcd\x0a\xcb\x43\x26\xf9\x0f\x0a\xa3\x3a\x8c\x4a\xfb\xbd\x5f\xcc\x4e\x5f\x65\x1d\xc5\x6c\x01\xd9\x8d\xed\xc7\x96\x79\x76\xe7\x73\xb9\xc7\x62\xea\x2b\xc1\xc7\x7d\xc1\xe4\x03\xd1\x89\xb3\xfe\x8e\x89\xb2\xab\xe1\xd7\x0f\xca\x8e\xa1\x5b\x3b\x36\x51\x37\xb6\xed\xc7\xff\x16\xf3\xb9\xf8\xf7\xce\x23\x63\xb4\xec\xee\xd8\xa7\x47\x5d\xd4\x09\xc5\xde\x93\x47\xf3\x79\xaf\xbb\xb9\x27\x52\x74\x34\xeb\xed\x3e\xd0\x1d\xb1\xf1\xf8\x51\x22\x26\x33\xb1\x96\xbf\xd8\xd9\xe9\x57\x5f\x6c\x3f\x2e\x90\x96\xa0\x51\x15\x92\x8c\xfc\x69\x23\xc4\x25\x8e\xa8\x28\x04\x8c\xef\x75\x07\xd9\x6e\xf0\x78\x27\xe7\xb0\x6a\x2f\x48\x77\x44\xb8\xb0\x23\x3a\x1d\xda\x47\xfa\x0f\x07\x44\xb0\x1e\x68\xab\xb8\x2d\xd1\x7f\x48\xdb\x6d\x53\xb9\xa0\x78\x9e\x11\x7b\x3d\x83\x72\xce\x9d\xbe\x74\xf9\x96\xb1\x62\x3b\xcc\xb9\x72\x28\x48\x97\xdf\xa4\x8f\xa1\x43\xfb\x5a\xdd\x65\xc4\x78\xa4\xc9\x89\x38\x3f\xb8\x9d\xa2\x6f\x9f\x26\x01\xd7\xc1\x45\x49\xc9\xbf\xd4\x89\x61\xb9\x13\xd9\xcc\x73\xe3\xc9\xc4\x70\x11\xf7\x2a\x6d\xba\xda\x9f\x88\x72\x05\x38\xeb\x1a\xf5\x0c\x42\x56\x92\x64\x10\xb1\x8d\x5e\x9f\x77\x3a\x7b\xb2\xdd\x46\xb1\x23\x6e\x45\x40\x02\xa3\x23\x46\xeb\xe5\x9a\xfd\x02\xe0\x88\x89\xdc\x7f\x0a\x7e\xaa\x49\x8f\x68\xbf\xbb\x37\x4a\x27\x7e\xc6\xc4\xe9\xe8\xac\xef\x9f\x6e\x6c\x8c\xce\xd8\x6c\x70\xa4\xc9\x8c\x7a\x97\x3a\x89\x33\xe7\xd0\xf7\x18\xc4\x69\xf7\x0c\x84\x5d\x55\xe0\x70\x40\x7c\x4a\x29\x44\xe5\x4e\x73\x2d\xac\x78\xc5\x42\x48\xdd\x56\x25\x3f\x4a\x0c\x12\x78\xb6\x1c\x81\xd9\x59\x59\x3b\x25\xa6\x13\x8e\x5a\x55\xf9\x7c\x26\x1c\x91\xa0\xd3\xf9\x37\x8b\xf3\x7d\xdb\x2f\x1c\x7f\x5c\x9d\xc7\x57\x42\xea\x59\x36\xc8\x2d\xc8\x9c\xf5\xca\x0c\x52\xe5\xaa\x4e\x5e\xf3\x54\x9d\xf5\x8d\x22\xa9\xce\x98\x30\x83\x15\x38\xd8\xcc\xb3\x69\x87\x2b\xa1\xa8\xbe\xd4\xc5\xe6\x19\x04\x70\x40\x34\xa5\x34\xa1\x66\xf5\xaf\x57\xf3\x0e\x9d\xad\x69\x79\x2d\x83\xca\x7a\xc9\x5c\x27\x0b\xb3\x65\x15\xb8\xb3\xd7\xc3\x74\xcf\x66\x2a\x45\xaa\x78\x72\x08\xed\x62\x50\x5a\x05\x9c\x0d\x64\xb1\x3e\xa5\x50\x5e\x98\x00\x4a\xda\xc8\x70\x99\x0d\x15\x6e\xdc\x2e\x0c\x33\x63\xb8\xc9\x94\x33\xd5\x7a\x20\x8a\x6a\xb9\x65\xda\x5a\xaa\xb7\x05\x23\x4f\xc2\x79\xe6\x16\xbe\x5a\xd5\xf5\x36\x5a\xd8\x17\x9e\x4c\x52\x44\x2f\x9a\x6a\xdb\x8e\x8c\xd8\x49\x28\x4c\x57\x08\x97\xb4\x1e\x68\xac\x79\x2e\xeb\x1d\xb7\x8b\x95\x41\x9c\x35\xfb\x5e\x97\x2b\x43\x7c\xb6\xca\x63\x5a\xd7\x00\x38\x36\xe1\xb5\x4d\x4a\x67\x6e\x0b\x8d\x20\xc0\x66\x41\x43\xb3\xd2\xe1\xda\x52\x43\x08\xb1\x69\xd4\xd8\x14\xa2\x55\x8d\x21\x3a\xab\x63\xb1\x25\xd6\x79\x67\x5e\xbd\xfe\x78\x7c\xe4\x4e\xb9\x9a\x09\xf4\xba\x2e\xb2\xcf\x8f\x31\x19\x93\xcf\x1c\x9c\x4f\x17\xe1\x6c\x2d\x9c\xad\xc9\x48\xaf\x5d\xf3\x49\x38\x5c\x33\x2d\xd7\xd7\x9c\x8e\x74\xaf\xc4\x6c\xc6\xcf\x05\x1c\x49\x03\x83\x22\xc3\xbd\x69\xa4\x04\xec\xf6\x52\x5a\x27\x6f\x41\x89\x77\x69\xad\xd9\x4d\x88\x28\xb8\x2d\x7a\x1f\xf0\x99\x58\xdb\xf2\x52\x9f\xa1\x1f\x45\x13\xc1\x4b\x2e\x43\x35\x78\x15\x13\x45\xbd\x7d\x49\x1c\xbe\xf6\xf4\xf8\xf8\xad\x03\x46\x51\x33\xad\x36\xb3\x56\x32\xbe\xf2\x85\x2a\x1c\x77\x6a\x80\xd5\xe5\xda\xab\xa3\x4f\xa6\xba\xb7\xb1\xd9\xdb\x7e\xb4\xfd\x78\x6b\x77\xfb\xd1\x9e\x6a\xb7\xd5\x5e\xf1\xdc\x6e\x93\xee\x1c\x35\x9c\xac\xab\xf5\x70\x76\x18\xca\x50\x9b\xd9\x9a\xcf\xd5\x7f\xf5\x16\xa1\x61\x35\x8b\xc2\xf6\x02\x0a\x0d\x78\x1f\xbe\x3d\xde\xff\x54\x20\xbe\x9b\xb5\x5a\xf4\x14\x65\xad\xd4\x5a\x28\x67\x9a\xcb\xc0\xbc\xfc\x88\x95\xb0\xa4\xe3\x38\x19\xc8\x8f\x9f\x4e\x5e\x1d\xbd\x28\x60\x3e\xf1\x4a\xb2\x2e\x1b\x8d\x74\x03\x5b\xdf\xbc\x2c\xea\xee\x64\x75\x5f\xc5\xc4\x2e\xa8\x7d\xff\x28\x7b\x8f\xcc\xdb\x0d\x67\x19\x13\x1f\x8c\xa5\xf5\x67\xc2\x41\xd6\xff\xdb\x57\x1f\x4b\x23\x7a\xfc\xe7\x96\xb7\x32\x6d\x2a\xd7\xf6\x4f\x4e\xf6\xbf\x17\x8d\x7b\x5d\x2f\xb3\xf9\x86\xb5\x6e\x66\x55\x38\x97\xe7\xf3\x75\xa2\xad\x63\x2e\x13\x45\x29\xd0\xe3\xa7\xaf\x0f\x9e\x7d\x5a\xbb\x09\xf5\xc5\x1a\x5f\x1b\x85\x62\x32\x5c\x93\xfc\x4a\x0c\xd7\xfe\x1f\xa7\xa3\x3b\xce\xff\x83\x1d\x5a\x69\x70\x97\x22\x75\xaa\x8b\x93\xc0\x17\x9c\x08\x3a\x10\x1e\x6e\x87\xef\xa8\xbf\xa0\x47\xd6\xa2\xd8\xf3\xac\xae\x29\x5d\x81\x22\x61\x71\x9c\x0b\xc8\x14\x23\x0c\x47\x44\xe5\xc6\x71\x5c\xa9\xb6\xf6\xf6\xf8\xe8\xc5\xc1\xc9\x1a\x47\x58\x6b\x47\x42\x0c\xd7\x50\x9e\xac\x39\x9d\xb8\xe3\xac\xf9\xb1\x5e\x8b\xe4\xe4\x6e\x6d\x26\xc4\x9a\xd3\xc9\xc0\x74\x9c\x35\x21\xb5\x0a\xc5\x0c\x3b\x28\x8d\x26\x6e\x18\xcd\x07\x8c\xa7\x28\x8d\x66\xd3\xfb\xe3\x34\xff\x61\x80\x76\xb6\xf3\x29\xe5\xac\x30\xcc\x03\xbb\x3c\x38\xf0\x0b\x3e\x3b\xbe\x91\xef\x55\x34\x15\x4a\xdf\x19\x35\xe9\xbe\x84\x6f\x70\x66\xe5\x2b\x22\x4b\xcb\xec\xe8\xbb\xe1\x6f\x16\x63\xce\xae\xc8\x31\xb1\x4f\x50\xf8\xdf\x5e\xc5\xe4\x8b\x26\xc5\x90\xb6\xbc\xac\xff\x90\x49\x77\x04\x11\x93\xee\x39\x8c\x58\xb7\x3f\xda\x8b\x32\x4d\x77\x64\x34\x78\x44\x20\x3a\x1d\x9d\xa5\xcb\x53\xed\x5e\xf4\x43\x16\x12\xd3\x59\xa9\xa7\x30\xeb\x65\xdb\x2b\xd0\x5f\x98\x6b\x7c\x7d\x81\x2d\x0d\x93\x10\x69\x8b\x9d\x1c\x2f\x9f\xb5\x60\x66\xb0\xea\xcf\x5c\xbf\x3f\x63\x33\xd7\x4f\x91\x99\x59\x7f\x6e\x38\x22\x0b\xa8\xf8\xec\xca\x00\x04\x3f\x47\xe6\x63\x4c\xbe\x72\x33\x72\xa3\xfb\xa5\x5d\x78\x0b\x8c\x5c\xba\x3c\xe3\xd3\xb6\x46\xb7\xb4\xdf\xa5\x19\x59\x29\x92\xa6\x46\x57\x52\x7f\x38\x4d\x4f\x95\x46\xcb\xcd\xf1\x30\x3d\x9d\xc5\xa0\xba\x88\x1f\xb8\x11\x53\xb8\x88\x78\x00\x1f\xb8\xbc\x34\xa7\x9a\xc4\xb4\x1c\xa0\x53\x0e\x0d\x1a\x93\x77\x1c\x72\x34\x6a\x02\x85\x6c\xb0\x46\x29\x4a\xa7\x2a\x7f\x72\x91\x76\x70\x3b\x15\x81\x0e\xe5\xb9\x11\x62\xb9\xf0\x2a\x0e\xc0\x65\xee\xb5\x5f\x3e\xed\x92\x6e\x0b\x6d\x86\x56\x71\xda\xb4\x24\xb8\xba\x5e\x75\x09\xa4\xcb\x0d\x1c\x97\xf7\x53\xb9\x96\x0a\xaa\x54\x58\xa4\xdc\xbf\xc2\x84\xd7\xbb\x8b\x0c\xdc\x0d\x10\x46\x90\x31\xe5\x94\xc3\x66\x5b\x37\xf3\x64\xc9\xfc\x88\x29\x67\xa3\x39\x84\x21\x42\x18\xb6\xdb\xcb\xb5\x4a\xb8\x0a\xac\x25\xea\x6a\x6d\x15\xb5\x46\x58\x6b\xd4\x6e\x3f\x33\xb5\xce\x41\xb9\xe7\xc5\x76\xc8\x6b\x5d\x60\xad\x8b\x3a\x58\xb9\xb8\x29\x01\x28\x91\xe0\xb3\x66\xbf\xdf\x7a\xe1\x33\x2c\x16\xa1\xec\x10\x10\x7b\x1a\x03\x80\x0c\x01\x9a\x8e\x31\x18\xe5\x54\x9c\x35\x9d\x10\x1e\x36\xaa\x2c\xa8\x24\x59\x79\x1c\x8e\xee\x08\x2a\x2f\x60\xd8\x21\x48\xda\x71\x9c\xb2\x1a\x73\x24\xeb\x4f\x98\x2e\xab\xef\x4d\x7f\x1f\x57\xf9\x58\x4e\xe5\x19\xb3\xfd\xe8\x54\xb7\x7e\x25\x99\x01\x1e\x4f\x26\xa5\xee\xde\x96\xc0\xde\xb7\xbc\x2e\x70\xa3\x8c\xe7\xc5\x3f\xab\xc5\xbd\x85\xe2\xdf\xd5\xe2\x4d\xf0\x3d\x09\x81\x67\xfa\xb0\xda\xff\xf1\x0a\xed\x7f\x0b\x6b\x0f\xd1\xa0\x80\xa7\x2b\x2a\x6e\x97\x2a\xe2\x48\x3e\xc9\xf2\xc1\xde\x09\x22\x61\xad\x45\x1c\x82\xf0\x3e\xc9\x4e\x27\x35\x43\x70\x96\x2f\xbc\xd3\xb3\x24\xe3\xa8\xaf\x71\x56\x4a\xa1\x26\xcf\xcb\xdc\xe1\xb7\x24\x65\x96\x20\xc9\x5b\x49\x4e\xd2\xad\x5d\xda\xdc\x2f\x53\x24\xa5\x7b\x61\xed\x30\x45\xe1\x35\x1e\x2b\xe0\x79\x59\x65\x34\xe5\x75\x59\x00\xff\xd2\x96\x02\x76\xf3\xdb\x9a\x9b\xf6\x9c\x45\xb2\xf5\x1e\x7c\x91\xec\xf4\xac\x18\xe9\xeb\xcc\x5c\xfe\x22\xd3\x08\x18\x0a\xeb\xef\xd3\x38\x19\xd3\xa2\xdb\x97\xec\x8b\x74\x67\x17\xe1\x48\x13\xda\xa7\xef\x4c\x83\x3e\xc2\x2a\xad\xda\x3b\x1c\x2f\x3a\xd7\x94\x9b\x39\x09\xa4\xd9\x86\x6e\xcb\xec\x8c\xae\x3d\x72\xef\x99\x3f\x79\xbd\xf3\x76\x5b\xb9\xe7\xc8\xb5\x64\x9f\x2a\xf7\x9c\x99\xc7\x10\xb9\xb3\xd9\x73\x76\x7c\x06\x20\x16\xf8\xc4\x80\x33\xd2\x2a\xab\x89\x8e\x28\x83\x3c\xc6\x53\x66\xbc\xfc\x3a\x0a\x87\x58\x35\xc0\xfe\xfd\xca\xec\x18\x60\x12\x70\xbd\x12\x8a\x82\x60\xc7\xe2\x94\x22\xa9\xdc\x8b\xea\x06\x4e\xbb\x1f\x61\xf7\x17\xd9\x3c\x50\xeb\x03\x33\x98\x18\xb2\x43\x9f\x75\xd7\xeb\x19\xdb\xd3\x54\x85\xd0\x53\xee\x79\x02\x59\xdb\x61\x62\x69\xf7\x45\x65\x11\xcb\x96\x60\x79\x11\x55\x36\x7d\x52\xdc\xac\x7d\x7b\xf7\xf6\xa5\xd6\xd3\x13\xf1\x2b\x16\x33\xdd\x5f\xaf\x12\xb4\x99\xaa\x20\x2c\xd4\x9d\xbe\x74\xf9\x70\x78\x70\x2d\xa4\x7e\x1b\xce\xb4\x90\x42\x11\x67\xaa\xa2\x73\x25\x66\x33\xa7\x22\x99\x32\xc6\xf5\x2c\xba\x9a\xc6\x9a\xfb\x13\xd1\x6e\x1b\xaa\x74\x39\xb9\xf7\x3f\x7a\xd2\x9d\x44\x7c\x28\x86\xe0\x7f\xf2\xa4\xab\x23\xcd\x27\x18\x9d\x92\x10\x09\x31\x7a\xbf\x96\xfa\x11\x4a\x45\xaa\xd4\x09\xbd\x57\xe4\xa7\x24\xb3\x10\xa3\x5a\xea\x5a\xe8\xf0\x4a\x44\xb1\x5e\x6e\x33\x69\x6e\x63\xd0\x5a\x68\x50\xe7\xb1\x23\x82\x49\xb8\x0f\xde\x7b\xc2\x55\x62\x36\x8d\xe4\x4c\x7c\x3e\x79\x0b\xfe\x9d\x77\xef\x7f\xf5\x84\x3b\xd3\x5c\xc7\x33\x08\xa2\xfc\xf7\x27\x71\xab\x13\x08\x02\xaf\x3c\x4b\x96\x07\x84\xb1\x3d\x07\x2f\x4e\xc1\x0b\x97\xab\x4c\xcf\x08\x9d\x7f\xd4\x3f\xd2\xa1\xb0\xfa\xc8\xb2\x70\x72\x3a\xde\x9a\x83\x04\xd8\xdd\xe3\x99\x8a\x12\xa7\xfe\xf1\x50\x9e\x93\x2e\x70\x0a\x61\xe5\x15\xef\x6c\xd2\xbe\x62\xb7\x64\xc2\xcb\x21\xf5\x05\x13\x3f\xd2\x24\x08\x89\xa4\x83\xb0\xe3\x00\xda\xc1\xdc\x0b\x69\x02\x8a\x26\xc5\x79\x27\x11\xee\xb9\xd0\xfb\x93\xc9\x49\x3a\x2f\x2f\x05\x1f\x0a\x35\x23\x94\x82\xff\xa1\x34\x5f\x29\xdf\x10\x56\xb9\xb0\x93\xb4\xb7\xd9\xed\xce\xe7\x5b\xdd\xee\x1e\xcb\x5e\xd1\xdc\x07\xef\x47\xc3\x3b\x26\xf3\xf6\x66\x42\xe1\xa7\x24\xa3\x90\x68\x9a\x9e\x87\x30\x45\x74\x59\x11\x8d\xe9\xe0\xad\x24\xb1\xcb\xa9\x47\x1a\x01\x8c\x49\x14\x62\x64\x17\xba\xcf\x88\x04\xe1\xfa\xdb\x46\x4f\x4b\xac\xdf\x55\xba\xd1\x54\x48\x22\xdc\x60\x0a\xc2\x0d\xde\xc3\x7a\x77\xd9\x6d\x80\x74\xe5\x1b\x55\x39\x78\x6f\xc0\xac\x37\x1f\x7a\x06\x41\x5f\xbb\x7e\xdf\x86\xf2\x49\x77\x26\x74\xba\xfd\xec\x4c\x11\xed\x72\x1b\x72\x66\x74\x86\x12\xba\x77\x53\xa3\x8c\xfa\xdb\xae\x0f\xd2\x35\x86\xdd\x33\x25\x86\x42\xea\x90\x4f\x66\x06\xec\x09\x98\xbd\xea\x06\x6f\x68\xbb\x4d\xa4\x9b\x52\xbf\x29\x79\x63\xb4\x5c\x3c\x09\x4c\xe3\x2b\x84\xeb\x7f\xe8\xe7\xca\xca\x4c\xc8\x21\xb9\x36\xd3\x38\x20\x35\xf8\x38\xcf\x22\xa9\x85\xd4\x1b\x06\x03\x07\xa3\x0d\xc1\xa0\xee\xe1\xaf\xd2\x56\x91\x2e\xf7\x23\xa5\x09\x5e\x89\xa9\x78\xe6\x4a\x2e\x2c\x14\x78\xbe\x27\x5c\x1f\x78\xcd\x5e\x10\x2e\x37\x12\x20\xd7\x7c\xc3\x10\x30\x56\xd9\x48\xd2\x15\x7e\xb1\xcf\x46\x2c\x09\x90\x6e\x70\x6e\xfe\x39\x36\xff\xbc\xac\x6c\x63\x5b\xaf\xf4\xc6\x22\x99\xcb\x98\xcf\x0b\x2e\x31\xbb\x65\xc6\xe4\x46\x82\x55\x95\x07\xca\x1d\x4d\xf8\xf9\xcc\x33\x12\x60\xad\x4b\x69\x1f\x75\xfc\xf9\xfc\x19\x49\x8f\x08\x43\x76\x9f\x40\xc4\x48\xc0\x34\x41\x45\xdf\xe5\x30\x62\x9c\xcc\x20\xa2\xe0\xb3\x1a\x3e\x52\x8d\xae\xf9\x2e\xb3\xed\xfc\x1d\x43\x6f\x62\x97\xb7\xdb\x84\x68\xa6\xe7\xf3\xfb\x84\x9e\x8a\x33\x16\xbb\x9c\x08\x8c\x4a\x33\x35\xd8\x07\x49\xe2\x52\xb4\x81\x4e\x48\x08\xb3\xd2\xa0\x66\xb6\xaf\x20\x0d\x0f\x8c\x28\x8c\x48\x64\x2c\x0f\x30\xea\x9c\x22\x21\x04\xae\x0f\x31\x89\x8a\xe3\xb9\xea\x5b\xf0\x07\xf7\xd3\x48\xe9\x99\xe7\x27\xde\xbd\x15\x33\xdf\x25\x06\x0c\x65\x7d\x7c\x28\x0d\x48\xb0\xfb\x73\xf4\x8f\xda\x39\x4a\x20\x66\xd2\x0d\x80\x33\xe9\x0e\x21\x60\xd2\x15\x80\xf6\x68\x1e\xc9\xec\x5e\xb0\x13\xb3\x03\x8f\x0b\x07\xfb\x5a\xf9\xa2\x04\x96\x48\xb8\x6f\x79\x3b\xe0\xd7\x90\x8b\x74\x79\xe5\x68\xd7\x6d\x0d\x6e\x09\x07\x81\xaa\xa5\x17\xb4\xdb\xe1\x60\x1f\x6f\x12\x29\x37\x04\xe5\x5e\x9a\xb7\xb7\xf8\x22\x18\x28\xd7\xc8\x51\xf3\xca\x90\x02\x48\xd7\xa7\x56\x19\xfa\xfa\xb7\xca\x90\x72\xcf\xc9\xa2\x2e\xd4\xa0\x50\x8f\xc9\x2f\x09\xd2\xbd\x80\x54\x67\x55\x55\xea\xfb\xb6\xfa\x2a\x08\x6a\xb2\x63\x4f\xc1\xc4\x68\xb3\x85\x62\xf4\x63\x51\x9d\xbd\x32\xe5\x66\x0c\x6f\x56\xea\xb1\xd2\x93\x10\x2d\x38\xc6\xa5\xaa\xc6\x71\x97\x82\xc2\x30\x2c\x51\x29\xb2\xde\x05\xdc\x65\x46\x23\x07\xf3\x8c\x87\xb8\xe9\xb3\xa4\x46\xc5\x3c\x8d\xcf\xcc\x10\x9d\xd1\xad\x03\xdc\x13\xa7\xf1\xd9\x7c\x7e\x1f\x7a\x2d\xb8\xf4\x5a\x95\x4b\x2b\x4a\x15\x9b\x38\x35\x24\x55\x6e\x48\x66\xfe\x25\xe5\x8e\x81\x33\x32\x62\x31\xf8\x4c\xc0\x98\xc8\xc1\x77\x79\x3a\x3a\x73\x85\x67\xff\x8e\x2a\x72\xaa\x38\x84\xf1\xfb\x0a\x23\x7c\x7f\x51\xa3\x26\x4e\x4b\x2c\x45\x1a\xbd\x69\x52\x84\x84\xa2\x3e\xa7\x4f\xe3\x33\x46\x42\xc6\xcd\xf6\x8d\x30\xb4\x88\x96\xf0\x06\x39\x88\xdc\x90\x5d\x91\x10\x22\x37\xa4\x5e\xe4\x5e\xa6\x0f\x97\x14\x22\x9a\x3b\x60\x8b\xc0\x63\xe5\x5e\xf5\x03\xd7\xef\x07\x2c\x70\x7d\x8a\x63\x35\xbb\xce\x8c\x36\xed\xb8\x5f\x71\xf5\x22\x1a\xe9\x9c\xb8\x11\x68\xb8\x9f\x7a\xca\x95\xf0\xcb\x13\x89\x25\xca\x10\x22\x18\x81\x5f\xba\x09\xa8\xcc\x90\xbf\xcb\x53\x79\xd6\x6e\x3f\x23\x5b\xe5\x5b\x88\xaa\x42\x7b\x58\x13\xb0\x26\xbb\x17\x5e\xac\x40\x79\x0a\xb8\xc7\x55\x02\xdf\x72\x13\x20\x56\x8d\x11\x48\x65\x32\xe1\x2a\xdb\x7d\x1a\x38\x3b\x3d\x83\x80\x21\x64\x57\x41\xc8\x88\x66\x5d\x58\xd8\x24\x76\x41\x66\x42\x7f\xb2\x02\x89\x94\x25\x46\xb6\x73\xa0\x10\xdb\xa5\xe2\x60\x22\xb8\xca\x9a\x29\x74\xb3\x67\xb5\x6c\x9f\x3e\x0b\xed\xb8\xdc\x60\xc1\xb2\xcc\xcd\x80\x34\xd2\x9b\x16\x12\x98\x83\x30\x86\x66\x40\x30\xc6\x34\x0b\xe0\xcb\xb4\xaa\x18\x2f\xd0\xc4\x67\x24\x5f\xa9\xb5\x30\xa1\x70\x6f\xf4\xa4\x40\x85\xbe\xa8\x70\x21\x9e\x99\x35\x09\xc4\xb2\xbe\x8a\x1d\x3f\xe1\x8c\xa7\x07\x5f\x94\x96\xc2\x88\xfa\x6a\xaf\x3b\x9f\x73\xd4\xf2\x02\x41\x14\xf4\x68\xaa\xcd\x07\xaa\xdf\xc0\x85\xea\x3c\x40\x18\x48\x4e\x33\x7b\x33\x54\xcc\x89\xe5\x50\x8c\x42\x29\x86\x85\x4b\x73\x18\x05\x78\x6e\x38\xc8\x7e\x78\x65\x46\x1e\xa9\xcc\x42\xe4\xd3\xa9\x90\xc3\x67\x17\xe1\x64\x68\xa6\xbd\x4e\xee\xda\xfd\x29\x5c\x19\x0d\x45\xbf\x38\xe0\xe3\x4a\x48\x7d\x14\x0d\x45\x76\x72\x6a\x81\x3c\x53\xe5\x13\x54\x7a\x9f\x50\xa3\xe5\xdf\x57\xf8\xcf\x48\xd5\x19\xf6\xe8\x2a\xac\x50\x66\xf9\xec\xe9\x0f\x31\x90\xdd\xd2\xfa\xdf\x67\x1c\x85\xf7\x45\x87\xc5\xae\x3f\x9f\x77\x21\x8d\x63\x8c\x8b\x08\xcb\x4e\x11\xa1\x88\x4c\x37\xf0\x02\x18\x7a\xfb\xb8\x83\x84\xa7\x61\xe4\x71\xa3\xbd\xa0\xf2\x40\x52\x4d\x00\x66\xff\x57\x10\xfc\x3b\x14\x37\xff\x0a\x45\xa4\x8a\x49\xd3\x0e\x47\x97\xc5\xa5\x27\x51\xc4\xf8\x5e\xaf\x43\x14\x76\x4e\x2b\x0b\x74\xad\x16\xda\xec\x18\x71\x04\x57\x9e\x82\x71\x26\xf0\x93\x06\x16\x72\xad\xc8\xa9\x04\x75\x56\xa3\x92\x59\x63\x39\x3b\xf7\x55\xcd\x1e\xa2\x14\x06\xe8\x3a\x28\xd9\x1d\x48\x03\x09\x5a\x8a\xad\xd0\x15\x73\x38\x20\xea\x20\x15\x77\x23\x11\xd6\x95\x6a\x8a\x2d\x59\x06\x07\x71\x1d\xc0\xf2\x9d\xc9\xe4\x2f\x4e\x61\x2b\x00\x81\xd7\x81\xac\x5e\xa3\x4c\xfe\xea\x9c\x76\x01\x2c\x04\x75\x80\x17\x2f\x56\x26\x7f\x79\x96\xbb\x04\x1c\xc2\x3a\xf0\xcb\x37\x2d\x93\x85\x13\xdf\x11\xf8\x30\x83\x09\x5c\xc3\x10\x5a\x70\x05\x17\x95\x2e\x96\x4a\xeb\x3a\x51\xcc\x07\xcd\x66\x20\xd8\x04\x62\x76\x0d\x9c\x19\xdd\xb3\x05\x21\xbb\x82\x88\x5d\xc0\x63\xc6\x18\x91\x6c\x44\xeb\x2e\x76\x42\xd4\x74\xb5\x93\x44\x69\x20\xe0\xe2\x99\x74\xd2\x7c\x25\xc0\x68\x42\xbc\xeb\x94\xf4\x2d\x0a\x17\x2b\x76\xa1\xc3\x7b\xe5\xca\x30\x5d\x59\x77\xb3\x52\xf7\x7c\x65\xdd\xad\x72\xdd\x9a\x08\xed\x52\xd5\x6d\x53\x55\x41\xe4\xdd\x8f\xb0\x85\x4e\x2a\x6c\xe0\xa6\xc4\xa7\x1d\x23\xef\xa6\xda\x61\x4c\x0e\x9c\xa9\xe3\xc9\x86\xfd\x6f\x26\x01\xdd\x5f\xad\xc1\x98\x5c\x29\x30\xaa\x0d\xd1\x4c\x42\xcc\xce\x23\x8c\x1b\x8a\xf0\xfa\x9e\x70\x5b\xc0\xbd\x78\x70\x4b\x66\x01\xc4\x7b\x5b\x83\xb1\xf2\x6e\x15\xdc\x05\x46\xcd\x16\xc6\x8c\x1f\x13\x15\xa6\x87\x91\x09\xa5\x5e\x7a\x61\xc0\x2c\x47\xca\x41\xee\x14\x8c\x1b\x35\x99\x63\x82\x2e\x28\x8a\xfe\xf8\x84\xc2\x6d\xe3\x9c\x05\x91\x21\x03\x37\x88\x28\x70\x63\x26\xf0\x10\xf8\xb9\xf9\x7b\x5e\x99\x0c\xe4\xba\x25\xbd\xf3\x3e\x29\x5d\x50\xc8\x7d\xf8\x1c\xdd\x36\x2d\x88\x99\x76\x25\x46\x96\x47\x78\xb2\xcb\x37\x9d\x75\xc6\x44\x66\x6c\xaa\x53\x71\x36\x9f\x13\xf3\x87\xdd\x27\xb4\x6f\x56\x8d\x31\x26\xda\x6d\x27\x98\xf0\xd9\xcc\x3c\xc4\x83\x03\x45\x02\x7b\x3f\x3a\x30\x5a\x2b\x47\x5f\xa1\xad\x70\xc4\xaf\x44\x5e\x49\x41\x0c\x97\x92\x70\x33\x4b\xa6\x22\xfe\x2e\xfc\x34\xc5\xa9\xcf\x82\xde\x2f\x4f\xd5\x59\xdf\xfc\xc3\xc4\x40\x74\x9c\x35\xa7\xa3\xbd\x52\xb2\x8c\x67\xaa\x7a\x3e\xd1\xca\xbc\x9c\x79\x10\xa3\xa9\xe1\x8e\xf1\x96\xce\x98\x49\xf7\x8a\x50\x9a\x9e\xe7\x75\xcb\xd5\x42\xe5\x06\x4a\x70\x8d\x7e\x18\xa3\x32\xd8\xeb\x91\xe1\x88\x6c\x63\xb5\xd2\x11\x9c\x74\xc7\x68\x49\x5e\xf6\x4d\x91\x70\x5b\x7d\xba\x74\x5c\x1b\x0f\x62\x76\x1a\x83\x70\x2f\xcf\xbc\x3c\xd2\xe8\x92\xe2\xdd\xbe\x71\x7a\x2a\x7b\x7f\xe9\xc5\x30\xf5\x54\xe6\x59\x27\x01\x7b\xa6\x88\x00\x63\xaa\x8b\xc9\xd5\x4f\x71\x2d\xa4\xfe\x69\x54\x9a\x9f\x4a\x8c\x18\x87\x20\x09\x47\x64\xab\x8c\xf5\xa1\x22\xc6\x8e\xbd\x20\xd2\x3d\xa7\xa0\x40\xba\x43\x0a\x41\xdf\x2e\xa0\x74\x47\x83\x7c\x58\x07\x13\x61\x54\xac\xa3\x8f\x44\xba\x23\xc0\xd8\x83\xc5\x32\x8c\x48\xe8\x07\xaa\xdd\x76\xb8\xd9\x43\x6e\xd0\x6e\x07\x35\x4e\xc9\x60\x12\x06\x63\x07\x02\x45\x02\x4a\xc1\xa0\x90\xf6\xdc\x2f\x9f\xf2\x0a\x88\x58\xb7\x1f\xed\x85\x99\x2a\x1b\x75\x3a\x34\x32\x95\x9f\x29\xd2\x33\x83\x18\x84\xa7\xd1\x99\x67\xfe\xc1\x13\xdb\x5c\xc1\x0d\x4a\x97\xed\xd4\xd2\x09\xa8\x31\xfe\x74\xd9\xd1\xd8\x37\x6c\xca\x2c\xc4\xe0\x48\xa1\xbf\xd6\x4b\xf7\xb7\x18\xbc\xb2\xcd\xf1\x95\x25\xde\xc1\x65\x5e\x67\xdb\xbe\xf8\x98\xbe\x20\xce\x35\x9f\xc4\x02\xb7\xc0\x7c\xee\x04\x17\x22\x18\xa3\xb6\x6a\x1e\xe5\xa9\x38\x5b\x67\x2c\x46\x5f\x16\x7a\x3e\xca\x87\x64\x47\x0b\x44\x38\xd3\x77\x13\xd1\x78\x55\xa9\x74\x26\xa5\x16\xd4\x30\x5b\xb3\x74\xf5\xa0\x2f\x06\xe8\x02\xdb\xd7\x5a\x85\x7e\xac\x05\xb1\xb9\x10\x5c\x25\xae\xa2\x6b\x51\x7a\x5d\xc6\xe7\xe3\x1f\xe1\x82\x51\x96\x47\xc0\x99\x70\xa3\x3e\x5f\xe8\xe3\xe8\x23\x89\x41\x63\xca\x83\xc5\x7e\x6c\x51\xb9\xaf\x57\x8b\xfb\xd5\x90\xee\xe1\x0c\xf7\x1b\xfe\x42\xde\x51\x31\xdd\xf5\xc2\x25\x1b\x63\x96\x9b\x8d\xc6\x6d\x28\xa3\xfd\xd7\xfd\xe5\xb6\x18\x63\x1c\x8d\x70\xf7\x17\xe3\xfd\x20\x92\x3a\x94\xb1\x48\x32\xac\xaa\x64\x19\x1b\xfd\x20\x60\x6f\x0d\xab\xe1\xb5\xde\xf4\x18\x02\xb8\x53\xed\xf6\xfd\x94\xcf\x66\xe1\xb5\xf0\xce\x23\xc2\xe9\xde\x66\x42\x01\xaf\x3b\x05\xf6\x9c\xa3\x19\xbc\xad\x96\xe9\x96\x5a\xdd\xdd\xdf\x84\x72\x18\xdd\xd4\x39\xfb\x1d\x7b\x3e\x79\x8c\x7c\xc1\xb5\xb6\x4f\x1e\x6a\x71\x9f\x80\x93\x22\xe1\xc0\xfd\xb9\xd0\x5e\x49\x6f\xb8\x53\x6c\xbd\x6b\x64\x73\xe1\xd5\x2d\xa6\xfb\xad\x22\x3e\x18\x1e\x5f\xf2\xa9\xe5\x46\xad\xfb\x0b\x34\xbb\x43\x99\x02\x32\x0b\x59\xd0\xb4\x1a\x3c\x7b\x1e\x11\x45\x91\xeb\x73\x08\x58\x3c\x30\x72\x8d\xbb\xdc\xe3\x6e\x10\x79\x1c\x42\xd6\x33\x1c\x9b\xbb\xbe\xb7\xc5\x58\xdc\x6e\x73\x23\x6c\x22\x46\xc2\x76\xdb\x50\x76\x34\x35\xa3\xe0\xe7\xdc\x62\x0b\x64\x73\xa9\xfa\x39\x35\x55\xa7\x0a\xf9\xd7\x73\x31\xe2\xf1\x44\x13\x0a\x3e\xed\x0b\x16\xb9\x97\x7d\x7b\x11\x2f\x1b\x41\x11\x60\x25\xa8\x31\x9b\x03\x6a\x23\xac\x97\xe3\x73\xfb\xa3\x8d\x8d\xbe\xa9\x73\x3a\x3a\x33\xd5\x22\x16\xb9\xd3\x24\x22\xa8\xb8\x65\xa2\x64\xe6\xfe\x62\x12\x66\xa5\x23\xd8\xca\xe6\x3c\xcd\x6f\x0a\x1e\x67\x1e\x9f\x2e\x2d\x67\x5f\xfa\xad\x16\xad\xca\xfb\x96\xa7\x40\x79\x1a\x66\x9e\x00\x9d\x9a\x16\x10\x67\x36\x46\xe1\xb8\x4e\x2d\x23\x28\x5d\xeb\x3d\x2e\x41\x0b\x47\x04\x6f\x4b\x64\x70\xa5\xd1\x2e\x8c\x12\x82\x01\xf1\xeb\x8c\x59\xfa\xef\x19\x3e\x33\x9f\x6f\xe2\x8b\xb2\x3b\xe6\xb7\x22\x1a\xba\x20\x30\xb8\x85\xd5\x3b\x9a\x0c\xdb\xfd\xcb\x2c\x0e\x46\x0a\xe7\xe9\x38\x52\xe3\x52\xba\xc6\x76\x93\xee\x10\x84\x27\x60\xe4\x19\x51\xe1\x7b\xd2\xf5\x93\xc4\x12\x4d\x2f\x49\x9d\x63\x3c\x75\x8d\xed\x94\xbc\x4c\xd2\x9d\xd8\x78\x6c\x88\x58\x90\xc7\x87\xb0\x88\x31\x96\x0b\x81\x51\xbb\x1d\x99\x55\x1c\xb1\xe0\x34\x3a\x33\x25\xa7\x11\x6e\xfe\xd1\xc2\x89\xa6\x91\xd5\x63\xda\x37\x3f\x94\x11\xda\x7d\x1b\xa5\x53\x5d\x3f\x77\x0c\xca\x1d\x83\x6f\xd6\x10\xdb\x75\xf7\xfc\xfc\x8a\x13\xce\x57\x0f\x04\xf8\x34\x0f\x08\xcc\x90\x9d\x19\xf1\x0d\x13\xa6\xdc\x4b\xb8\x66\xeb\x3d\x18\x9a\xee\x50\x9e\x0f\x8d\x3c\xbf\x66\xeb\x5d\x58\x12\xea\xb3\xc1\x8c\x9d\xce\x60\x68\x84\xfa\xcc\x2e\xf7\xd0\x08\xf5\x21\x1b\xba\xe3\x9c\xc7\xb5\x98\x4a\x41\xb5\x9a\x41\x4d\x06\x13\x76\x3a\x81\x96\x01\x35\xb1\xa0\x5a\x06\x54\x8b\xb5\xdc\x71\xee\x0c\x6c\xb7\xb3\x98\xea\x75\xc6\x26\xd9\xdd\x93\x45\x6a\xf0\x08\xb9\x1e\x34\x19\xf6\xdd\xbe\xde\x2b\xf2\x46\xd8\x68\x0c\x79\xaa\x8d\x34\xc3\x08\xbb\xe5\x50\x0c\x32\x83\x09\xf5\x66\x8c\xb1\x09\x9d\xcf\xb1\x9f\x4d\x10\x30\xb1\x53\x6c\xe6\xdd\x58\x3b\x1a\x44\xa7\xb7\x14\xc3\x84\x8b\x20\x5d\x8e\xb1\x21\x3c\x5d\x83\x2d\x74\x78\xf3\xa5\x90\x28\x04\xf7\x34\xdf\x21\x70\xb2\x18\x3b\xba\x54\xe3\x79\x56\x63\xcb\xc3\x63\xba\x0b\xec\xe7\xa2\x71\x9b\x60\x00\x35\xfb\x64\x28\x65\x08\xca\x68\x28\x57\x29\x4e\xdb\x20\xe0\x2a\x8d\x99\x66\xca\x0d\x8b\xe0\x99\xf2\x48\x32\x2a\xda\x01\x01\x17\x94\x96\x7d\xdd\x25\xac\x62\xbb\xb7\xb3\xc8\x20\xc3\xfc\xd2\xb0\x9c\x4c\xd0\x95\x31\xe0\x25\x0c\xb8\xb1\xbe\x73\xfb\x1e\xd9\x5e\x09\xfd\xd2\xad\xe9\xaa\x90\x35\xfa\x76\x35\xa2\x0f\xef\xe2\x1b\x3d\x68\x9d\xb1\xc0\xe8\x6f\xdd\xfc\xd7\x56\xfe\x6b\x1b\x7f\x99\x9a\x41\x49\x21\x08\x99\x3c\x0d\xce\x20\xb2\xb9\x4d\x42\xc6\x58\xd4\x6e\x17\xba\x90\x69\x59\xd2\x85\x82\xf9\x3c\xd5\xae\x74\xbb\x4d\x48\xcc\x42\x6a\xe4\x34\xe1\x2c\xa2\x6e\x0b\x03\x8c\xf2\xac\x14\xf3\x39\x21\xc2\x68\x4f\xf7\x09\x3d\x0d\xce\x58\x64\x87\x58\x79\xa7\x07\xa9\xf6\xa6\x07\x8e\x93\x29\x6e\xda\x74\xb2\x65\xdf\x5a\x2e\x8b\xc6\xdf\x69\x70\xe6\x8e\x20\xca\x18\xaf\xb7\x7c\x97\xfb\x34\x38\x33\x60\x8c\xe4\x45\x21\x72\x6f\x05\x88\x99\x3e\x33\x46\x33\x42\xd3\x33\x04\xd4\x30\xa2\x2a\x76\x23\x9a\xe4\xc1\x80\x76\x7a\xf0\x8f\xac\x8c\xc2\x37\x7c\xd3\x2f\xe7\xbe\x29\xc2\x68\x96\x04\x87\x61\xc6\x86\xc1\x0b\x23\x67\x8b\x8b\x6e\x3c\x0f\xa2\xda\x0b\x06\xb8\xdc\xbb\x20\xe0\xfe\xda\x0b\x21\xf4\x82\x8d\x30\xa1\x5e\xb0\x17\xa6\x54\xf2\xc8\x16\x05\x20\x3c\x5e\xd2\xa3\x22\x16\xec\x85\x83\xc0\x0b\xb3\x20\x4a\x1b\x3d\x69\x79\x64\x7c\x3a\x3a\xeb\x1f\x1b\x45\x81\x9f\x8e\xce\x40\x43\xa7\x63\x2f\x5a\x5a\x1f\x5e\x89\x88\x9f\x97\x70\x2e\xe7\x62\x01\xce\xcc\x2c\x99\x5f\x99\x2a\x6f\x86\x31\xca\xf9\x38\xf8\x2c\x8b\xdb\x84\x19\xeb\xc2\x84\x75\xe1\x9a\x89\xfe\x6c\x6f\xd4\x6e\x4f\xf6\xfc\x34\x12\x60\xc8\xc8\x33\x16\x9e\xce\xce\xa8\xcb\xa1\xc5\xc8\x21\x8b\x4e\x27\xf8\x70\xc5\x9e\xb9\x3e\x5c\xb0\x43\xd7\x37\xdc\x7f\xb8\xce\x58\xcb\xb6\x99\x9a\x06\x9d\xde\x19\x9c\x9b\xca\x9d\x1e\x4a\x87\x29\x35\x45\x37\x6c\xea\x72\xb8\x63\x53\xd7\x87\x31\x33\xea\xe1\x8d\x29\x3c\xc7\xc2\x5b\x76\xee\x72\xd8\x67\xe7\xae\x0f\x07\x6c\xc8\x18\xbb\x35\x85\x07\xed\xf6\x98\x1e\x2b\x72\x05\xfb\x10\x43\xa7\x73\x4d\xe1\x97\xc2\x6c\x79\x43\xb8\x80\x89\xd1\xea\xae\x3b\xec\xca\x7a\x37\xdf\x67\x25\x77\xb6\xe6\x75\x87\xdd\xd9\x92\x59\x87\x6d\xc2\xa4\xc3\x36\xad\x72\x62\x00\xd3\xeb\x4e\x27\x83\xd5\xca\x60\xe5\x3d\x5d\x97\xe1\xce\x3a\xac\x57\x6d\x3d\xa6\x79\x5f\x57\x79\x5f\x69\xed\x63\x45\xee\xe0\x22\xc3\x76\x19\x87\x5e\x3f\x0b\x05\x5a\x9f\xce\xe7\x37\xeb\x8c\xdd\xa6\x77\x60\x16\x61\x2e\x62\xb7\xd0\xc7\x7e\x73\x1f\x9b\x89\x65\x47\x38\x9e\x32\x2e\xf9\x88\x3a\x30\xe9\x74\x70\xcb\x98\x55\x4f\x17\xfc\x59\x86\x42\x69\xdd\xed\x52\x2f\xb7\xb7\x6d\x0b\x62\x39\x84\x23\x76\x34\x9f\x9f\x9e\xf5\x53\xb4\x4b\xe4\x72\xe8\xfa\x90\x2a\x5e\x47\x14\x3b\x26\xdd\xbd\x6c\x4f\xcd\xe7\xdd\xbd\x20\xff\x7d\x44\xd3\xad\xf3\xd8\x6c\x9d\x1b\x2f\x86\x5b\x2f\x80\x3b\xef\x28\x3d\xb9\x7a\xa9\x98\xf3\x53\x4c\xae\xbe\xee\x3e\x7d\x5b\x4a\xce\xf9\x4b\xd5\x1d\xb8\x1b\x49\x89\xd1\x30\x41\x26\x63\xd2\x23\x96\x7b\xe5\xc5\xb0\xef\x05\xec\x3e\xf0\xba\xf0\xdb\x13\x60\x5e\xcc\x72\xc7\x73\xaa\x8f\x98\xf6\x2c\x40\x55\xdc\x98\xbc\x81\x1b\xe4\x87\x34\x19\x84\x84\x42\xe0\x06\x6c\x33\x3d\xb3\xaf\x28\x38\x81\xfb\x1b\x04\x84\x10\xb8\xca\xd4\x52\x2c\xb6\x60\x03\x77\xe6\xce\xd8\xfd\x8d\x17\x5a\x08\x49\x86\x7d\xe7\xa5\xca\xbc\xb0\xf9\xc8\xde\x57\x24\x95\x15\x48\xd9\xb8\x78\x1e\x0b\xc6\x2d\x6a\x19\x22\x41\x15\x11\x01\xdc\xfd\x0d\x01\xc4\xa9\x12\xf0\xdb\x58\x59\x4f\x20\x36\x13\x1c\xc0\xbe\xe1\x4d\xc9\xfb\x2a\x0e\x96\xd9\xa7\x22\x26\xaf\x9f\x1d\x00\xe0\xc4\xdc\x07\x5e\xaf\x34\x77\x61\x59\xbe\x7e\x29\xb1\xa6\xf5\xd2\x61\xfc\x82\xc3\xd7\x32\x43\xb4\x20\x2d\xaf\x8f\x5c\x1b\xaf\xd4\x37\x22\x38\xbb\x4c\x6c\xb8\x55\x2b\x5b\x04\x9f\x7e\x31\xd8\x68\x77\x0c\x91\x3b\x83\x90\xe6\x9b\xf2\x31\x96\xde\x47\xae\x66\x0a\x22\x37\x66\x61\xdf\x2a\x8b\x91\x3b\x73\x6f\xfa\xdd\xbd\x59\xae\x5c\x5a\x44\x66\xd0\xcd\x1c\xc7\x19\x8c\x27\xf5\x30\x26\x06\x86\xc1\x60\x42\xef\x27\xee\xbe\x3b\x63\x2a\x85\x3d\xf9\x13\x64\x0b\xba\x0c\xd0\x10\x24\x31\xa3\xee\x74\xf0\x64\x98\xe0\xb0\xe9\xbf\x73\x22\x8d\x91\xd2\xaf\x99\xb6\xa3\x36\xba\xe8\x75\xc1\xe1\x87\x4c\x97\x75\x5d\xab\xbd\x16\xc7\x1f\x30\xb4\x13\xdc\xe9\x41\x00\xaa\xc6\x13\x65\xf7\x51\x8b\x69\x57\xa4\x1a\x96\x72\x83\x8b\x70\x32\x3c\x8a\x86\x62\x96\xcb\xa8\x0b\xd6\xed\x5f\xec\xb5\x32\x69\x77\x91\x09\xa8\xa9\xb1\x30\xd9\xf5\xa0\x75\x7a\x71\xe6\x99\x7f\x5c\x1f\xce\x59\xa7\xc3\x3b\x64\x6a\xcf\x79\x90\x32\xf7\xd8\xa8\xdd\x1e\xed\xb1\x73\x4c\xd4\x26\xc9\xd5\xe9\xc5\x19\x4c\xd3\xb5\x3f\x87\x90\x82\x9d\x83\x85\x19\xc8\xa7\xa0\xcf\xd9\x79\x7e\xd7\x2f\xc9\x6c\x3d\xe8\x82\x72\x7d\x28\x27\x91\x7c\xad\x96\xce\x64\xd0\x33\x98\xa9\xdb\xd2\x23\x25\x62\x84\x77\x0a\xef\xf9\x96\x00\xbc\x5b\x74\xb7\xa0\xd2\xad\xca\x4a\xf7\xa2\xeb\x45\x03\x67\x2f\x14\x89\x31\x5b\x14\x63\x4c\x62\x82\xa5\xc2\x21\x5a\x0a\x5c\x7e\xa1\x2a\xf7\xb2\x54\x29\xbc\x7d\xe9\x00\xb6\xea\x88\x29\x8e\x3f\x21\x66\xcf\x90\xe6\x69\x3f\xae\x59\xd0\xf9\x9c\xd4\xbd\xb6\xbe\x9c\xc5\xc5\xef\x8b\x76\xdb\x58\xab\xb2\xdd\x5e\x38\x56\x8d\x41\x96\x52\x5b\x61\xec\xc0\x0c\x94\x1b\x2f\x5c\xc7\x4a\x9d\x7a\x6e\x6c\xca\x29\x2c\x86\x1e\xc8\x0c\xe8\x73\xae\x39\xe9\x42\x9e\x32\xa0\x5c\x3b\xb7\x21\xec\xdc\xbb\xb3\x45\xcb\xa1\x0e\xf5\x41\xdd\x4b\xf7\x92\x29\x77\xe6\xd5\x15\xb1\xfb\x4b\xcf\x0c\x61\xea\x29\x37\x4e\xb2\xae\x77\xbd\x72\xf4\xdc\x2c\xcd\x77\xa9\xdd\x10\x63\xdd\x33\xe7\x91\x9d\x11\x59\xda\x17\xa7\xda\xbd\x2e\x14\x47\x99\xdd\x1f\x28\xd4\x2e\x82\xf0\x28\x2a\x8d\x95\x86\x82\x99\xa6\x7d\x91\x0b\xbc\xb4\xa7\x50\xce\x84\xd2\x4f\xc5\x28\x52\x82\x3c\x53\x24\xc6\x00\x7b\x37\xa6\xc0\x17\xfb\x79\xe2\x21\xcf\xb0\x3d\xd0\xc2\x63\x51\x3e\x20\x2f\xa1\x6d\xe6\xd9\x4a\x01\xed\xee\x97\x2d\xa2\xb5\xae\xb1\x01\x5c\x85\x0e\x9e\xc6\xc6\x81\x3b\x63\x76\x9b\xb8\x37\xf9\x92\x3d\xae\x23\xd7\x22\x1d\x81\x99\xc8\xe5\x70\xdf\x2c\x08\xb5\x14\x82\x9a\x7b\xad\x9f\xa7\x51\x03\x87\x8a\x9f\xa3\xfb\x3a\xcf\x3d\x5a\x9e\xa6\x4c\x17\xcf\x22\x52\xf7\xfb\x11\x5a\xb4\x56\xe4\x0d\xb8\x3b\xf3\x9e\x29\x62\xa4\x9b\x99\xb9\x72\xec\x9a\x76\xef\x6c\xce\xa7\x7c\x28\x85\x1b\x93\x69\xf7\x36\xbd\x76\x93\x2f\x4a\xe9\xf6\x4d\x7c\xca\x8d\xe6\x1c\xb8\xfb\x10\xb1\x4d\xf4\x7f\x04\x83\xd0\x76\x15\xa6\x5d\xf5\x17\x16\x30\x82\xca\xa2\x07\xae\x3a\xa3\x89\x68\xb7\x31\x0e\x42\x94\x02\x86\x70\x76\x16\xee\x0a\x2a\x77\x46\x24\xed\x0f\xad\xb3\xcd\x7b\x46\x7a\xdd\xb2\x93\xf6\xb3\x4a\x03\xdf\x6d\x5e\x5d\x43\xe0\x9f\xee\xa6\x22\x23\x84\x91\x31\x4f\xb5\xb8\xd5\x69\x68\xa5\xd5\x57\xd6\x1b\xaa\x3a\x0e\xed\x2f\xe6\xa5\xe4\x99\x83\x78\xb6\x2a\x24\xb8\xaf\xd8\x15\x19\x93\x73\x05\xb1\x2b\xf9\x95\x80\xd8\x45\x3b\x13\x53\x14\xa5\x8a\x89\xab\xf9\xf9\x11\xbf\x12\xae\x8e\xde\x46\x37\x42\x3d\xe3\x33\x41\x68\x7a\x62\x2a\x17\xe5\x8c\x28\x3c\x4b\xc2\x3a\x07\xaf\xc8\x67\x45\xc2\x53\x71\x46\x8d\x95\x97\x1f\xa2\xfb\x0a\x38\x28\x08\x2a\xe1\x23\x0a\x24\xe8\xd2\xb1\x31\x06\x5d\x86\xa0\xdc\xe0\xdc\xfc\x73\x6c\xfe\x29\x85\x6d\x62\x02\xc4\x2c\x2c\x22\xf8\x00\x9c\x85\x38\x3f\x10\xb0\xcf\x8a\x14\x7b\xee\xab\x5a\xb8\xa0\x6f\x67\x2a\xc6\xdc\x8a\xec\x27\x9e\x97\xd0\x3e\x67\xaf\x8d\x9a\x1b\x58\xa9\x12\x30\x0c\xc1\x4b\x4f\x0d\xbf\x57\x22\x06\x2c\x9a\xa2\x8a\xa6\x68\x44\x33\xce\xd0\x34\xb6\xe7\xbb\x76\x5b\xb9\xef\x08\xe6\x32\x45\xa4\x43\xb3\x81\x74\xa8\x27\xc6\xa8\x0b\x15\x46\x21\xc3\xc8\x0c\x20\x6a\x1e\x40\xa0\x18\xef\xdb\x51\x04\x76\x14\xbe\x22\x8e\x69\xea\x50\xd2\xa2\x44\xb9\xfe\x07\xb3\xfb\x7e\x2a\x32\x32\x42\x26\x32\x63\x8b\x60\x84\x7a\x20\x8c\x98\x86\x40\xb1\x2e\x84\xe8\xae\x09\xde\xb6\xdb\x24\x43\x82\x85\xf8\x86\xda\xc1\xc3\x87\xfa\x48\x21\x65\x23\x80\xf7\x65\x78\x85\x7e\xe7\x43\xc5\xaf\xc4\xa0\xf6\x6d\x25\xd8\xa9\x14\xe6\x25\xa1\x27\xb6\x1e\xee\x76\x69\x29\xc4\xe8\xab\xb2\xa1\xc0\x82\xe8\x2c\x62\xbb\x74\x2f\x86\x13\x7a\x1f\xa3\xae\x12\x0f\xba\x1e\xf9\x60\x96\x18\x4c\x55\xe8\xe5\x6c\xa2\xca\xb1\x34\x93\xa0\x06\x04\xeb\x98\x5d\x6f\x73\xcc\xf6\x28\xf5\x50\xc5\x8e\xdb\x6d\x0b\x24\x66\x9b\xe5\xdd\xf9\x4d\x15\xd1\x02\x97\x91\x99\x9a\x49\x14\xe0\x88\xdc\x0b\x23\x71\x5d\x3e\x9f\x3f\x23\x3d\xda\x14\xcd\x32\x26\xd3\x08\x2e\xa2\x4a\xa4\x1b\xbd\x57\xed\xf6\x45\x38\xd3\x91\xba\x73\xad\xcb\x5f\x12\x9b\xd4\x13\x47\xfa\xa3\xf1\x50\xba\x1e\x5a\x06\xca\x98\x2e\x1f\x35\xd7\x02\xcf\x30\x1c\x28\xc1\x85\x37\xaa\x31\xc7\xc7\x6a\xa0\xa9\xc0\x6f\x82\x7b\xbf\x78\xbc\x52\x3e\x2d\x49\xa0\xe6\xb4\xc6\xab\x06\x56\x83\xd4\x8c\xac\x8a\x40\x6b\xb7\xb3\x5f\x50\x57\xcd\x9e\xf2\x0c\xec\x1f\xef\x8d\xaa\x44\x2c\x54\x35\xc7\xe7\x92\x54\xc7\x58\x32\x5d\x24\xbd\x3f\x91\x44\x60\x64\x5c\xce\xb7\x97\x8e\x8e\x34\xc8\xea\x29\x15\x66\x0c\x2b\x2f\x6c\xed\xf9\x94\xb6\xdf\x7e\x68\xce\xea\x92\xde\xef\x2f\x5d\x47\xd0\x74\x70\xa4\x89\x76\x39\xe6\xf7\x28\x85\x11\x28\x5d\x0e\x91\x5f\xbc\xae\xf3\x41\x95\xc7\x87\x31\x28\x2c\x9b\x3e\xf7\x5c\xe8\xf4\x34\xf9\xe9\xdd\xab\x21\x5e\x7f\x20\x72\xf0\x36\x1d\xb6\xf7\x53\x92\xab\x28\x4f\x0c\x82\x3c\x5f\xeb\x6a\x78\x73\x29\x8a\x50\x2f\xb0\xa1\x4c\x04\x9e\xaa\x33\x42\xe1\xf7\xaa\x00\x67\xcd\x6a\x42\xbb\xb4\x3b\x0b\x54\x34\x99\xd8\x9c\x3b\xbf\x93\xc5\xd8\xd0\xea\xc8\x30\x1a\x54\x13\x5a\xba\x55\xa6\x57\x04\xab\x34\xa3\x9b\xf6\xfa\x56\x8c\x8c\x09\x97\x3d\x7e\x8a\xa6\x4c\xaf\x1e\x84\x5c\x9d\x97\x6b\x55\xe1\xff\x5c\x91\x57\x52\xed\xed\xd5\x65\x27\xcb\x4a\xff\xfd\xef\xd5\xa5\xa6\xb8\x29\x16\xb4\x4a\xfb\x96\x36\x66\x42\xbf\x92\x5a\xa8\x6b\x3e\x29\x17\x9e\x48\xa2\xf1\xb6\x4e\x53\xa4\x6d\xde\x48\xa6\x37\x38\xd0\xae\xd1\x10\x6b\xe0\x1a\x02\x0d\xa1\x86\x48\xc3\x48\x83\xaf\x61\xa6\xd9\xf2\xd4\x17\x71\x9b\x30\x69\x28\xdf\x4c\xcb\xaf\x1b\xca\xb7\xd2\xf2\x61\x43\xf9\x76\x5a\xde\x6a\x28\xdf\x49\xcb\xaf\x34\xbb\x6f\x79\xbb\x09\x5c\x68\xf6\xa7\xd8\xb8\x7b\x1e\x78\x1a\xbe\x7a\x0a\xfc\x91\x27\xe0\xc8\x0b\xe0\xd8\xe3\xf0\xde\x8b\x21\x78\x8d\xb9\x5e\x60\xaa\x57\x64\x29\x23\x66\x66\x31\x7b\x8b\x66\x43\xb8\xd1\x8c\x88\xf2\xdd\x97\xd2\xf5\x08\xe5\x06\x98\xdc\x70\x08\xbc\x49\x1c\xdc\x92\x73\x0d\xd2\x6d\x0d\xb4\xc7\x31\xcc\x83\x9b\xa5\x28\x17\x72\xc0\x3f\x06\x70\x4c\x6d\x5e\xa9\x1e\x85\x3b\xcd\xba\x30\xd6\xec\x02\x6e\x35\xdb\x84\xfd\x3a\x84\xd1\x4f\x63\x8f\x83\x37\x36\xd1\xe4\x6e\x55\x53\xaf\x1a\x5d\x72\x08\x31\x93\xc0\xd9\x2d\x2a\xe1\x3e\x68\x37\x80\x5b\xb2\x8f\xe3\x00\xed\x0a\xcc\xcb\x1b\x83\x62\x1c\x34\x13\x66\x72\x0e\xea\xd6\x62\x0d\xdb\x34\x4e\xda\x98\x8c\x35\xd8\x14\xb7\x36\x89\x57\xcb\xf0\x53\x78\x56\x05\x85\x2a\x50\x9e\x8e\x89\x49\xf8\x0b\xa0\x32\x83\xa7\x68\x02\x87\x9a\x7d\x84\xa3\x3f\xd0\xea\x25\xd2\x4a\x2f\x81\x8f\xd5\x8a\x78\xc8\xe4\x97\xef\xbf\xc9\x52\x26\x84\x4b\x9d\xc0\x2b\xdd\x98\x36\x11\xc3\x5a\xe1\x6d\xed\xd4\xc8\x04\x7e\x6a\xf6\x13\x7e\x2f\x37\x97\xde\xe2\x22\x15\x77\xee\xd7\x2e\x75\x3f\x33\xdf\x02\xcc\xf1\x3a\x44\x6a\x12\xd9\x55\xfc\x31\xf9\x89\xcb\xe4\xfa\x34\xf7\x59\x48\xa3\x23\x31\x91\x47\x73\xac\x2d\x5a\xf4\x47\x98\x60\x33\xb3\x64\x6c\xf5\xb8\x54\x3d\x31\x4b\x7c\xdc\x38\x50\xe5\xb6\x06\xd2\x53\x2e\x4f\x28\x3c\xd5\x4d\x37\x67\x6a\x26\x41\x93\x31\x39\xd6\xd0\x82\x31\xf9\x6d\x3f\x6e\x82\x01\xec\xf0\x69\x65\x57\x97\xda\x33\xeb\x60\x83\xf7\x13\x0a\x27\xf5\x13\x5c\xb5\x66\x12\x78\x5e\x5b\x6d\x4c\x9e\x9a\xf9\x1a\x93\xa9\x86\x8f\x1a\x3e\x19\x94\xa6\x1a\x4e\x34\x1c\x6a\xe2\x8c\xf8\x64\x26\x1c\x6a\xfe\x2f\x81\x97\xcd\x58\xd9\x0c\x6a\xbf\x34\xfb\x06\xef\xff\xb0\xeb\xd6\xf5\x62\xb2\x63\x81\x19\xe8\xed\x8e\xc3\x2f\x48\x64\x89\x8f\x2b\x3b\xec\x4b\xc3\x0e\x7b\xaf\x61\xac\xd3\xad\xf3\x5a\xd7\x46\x3d\x87\x23\x22\x8a\xf0\x72\xe1\x72\x0c\x42\xc2\x43\x20\x9e\xbd\x0f\x18\x77\x39\x9e\x94\xe1\xfb\x30\x7b\x1f\xb1\x10\xef\xb0\x85\xf6\xfd\x28\x7b\xef\xb3\x51\xf1\x61\x11\x83\x75\x0c\xe6\xdf\x00\xff\x8d\xf0\xdf\x91\xcb\x61\xa7\xdb\xdd\xd3\x03\xc4\xd2\xa0\x63\xf3\x74\x78\xfb\xe4\x75\xca\x4b\x3a\x3d\xf0\xed\xf4\x36\x82\x52\x0d\xa5\x6a\xf1\x75\x35\xe7\xee\xbb\x15\xec\x3a\xef\xbf\x6b\x19\xc5\x8b\xca\xca\x96\xf3\xf7\xdf\x92\x77\xba\x49\x2e\x23\xab\xb1\xf9\xd9\x73\xee\x45\xe1\xb3\x6e\xc8\xc8\x99\xf2\x9c\xd8\x13\x70\xe3\x69\xd0\x46\xd6\x1c\xe2\x51\x09\x8a\x97\xef\x8d\xd4\x75\x43\x3e\x6b\x50\xee\x2d\x28\xd7\xfc\xbd\x41\x3f\x9e\x21\x7f\xff\x10\xe9\xff\x83\xae\xde\x3d\x90\xf9\x49\xca\x92\x98\x2f\xdd\x9a\xbb\x45\x27\x82\x06\xc1\xa4\x7b\x83\xb1\x95\x71\xb1\x9c\x2f\x34\x7c\x37\xac\xce\x3f\xa4\x10\x10\x8b\x40\x7e\x4e\x63\xf7\xe8\xd7\x15\x7b\xd4\x1f\xe0\xbc\x8d\xed\x9e\xf6\x8c\x6e\xf3\xad\xb1\xba\x66\xd8\x1f\x8a\x01\x6c\xf6\xd5\x90\xb3\xce\xb5\x3f\xf8\xb1\xdc\x34\x8d\xfa\x33\x0c\xb0\x6e\x8c\xf9\x38\xbe\x19\x9c\xb3\x7b\x31\xf0\xa6\x11\x87\x31\xf9\x61\x30\x20\x46\x59\xac\x9b\xac\x9b\x22\x5d\xee\x29\xce\x86\x99\x3f\x33\x7b\x46\x3a\xc7\x80\x2e\x53\xff\x90\x12\xcc\x44\x4a\xcf\xf0\xea\x7f\x86\xbe\x14\xec\x12\x54\xc9\xd3\x56\xf3\xd9\xa9\xd5\xeb\x82\xce\x49\xff\x10\x33\x80\x14\xfb\x55\xe3\x7e\xd5\xc5\x2e\x3c\x24\x01\x44\x74\x90\xa1\x88\xe4\x69\xb6\x09\x84\xe9\xc2\x9d\x51\xaf\x95\x6d\x91\x56\x92\x80\x16\x2b\x38\x62\x2d\x4b\xf5\xdb\xed\x75\xe9\xfa\xae\x3f\x48\x25\x21\x5a\x31\x09\x08\xc1\xc6\xe4\x83\x86\x0b\xd3\xed\x9b\x3f\xfd\xa3\x04\x71\xf8\x44\x28\x3d\x73\x28\x68\x41\x9c\x51\x38\xd1\x42\x39\xd4\x3e\x9d\xab\x28\x9e\x9a\x07\xc4\xc4\x09\xe2\x99\x8e\xae\x5e\x98\x97\xa1\x3c\x77\x72\x56\x7d\xa8\xc9\xa5\xb1\x6a\x6c\x23\x25\x02\x11\x5e\x5b\x20\xcf\x35\x71\x66\xe1\x44\xc8\x40\x0c\xb3\xe7\x50\x5e\x84\x7e\xa8\x8b\x17\x3c\xd0\xe1\x35\xf2\x76\x88\x0d\xf6\x15\xca\xf0\xff\x9b\x97\x08\x22\xe6\x13\x7b\x26\x19\x15\xb2\xbc\x95\x9f\x9f\xf1\x45\xfa\x5a\x5a\x3c\x32\x42\xba\x2a\x56\x8f\x82\x93\xa5\x3c\x3b\xd2\x14\xb8\x19\xc3\x0f\x3b\xb7\xe9\xd8\xcd\xec\xe2\xbb\x58\xe0\x6b\x31\x0c\x35\x8e\x37\x10\x8d\xac\xf1\x3e\x18\x7b\x12\xbe\x59\xde\xa4\x4d\x2f\xa1\x58\x56\xc7\xd0\x29\x98\x67\x45\xed\x16\x5f\xb4\xa9\xa6\x69\x57\x03\xe5\xf5\xba\x9b\xdb\x0f\x88\xda\xc0\x02\xda\xa9\x34\xec\xd1\x0d\xcc\xe7\xdd\xd9\xdd\xd9\xd9\xda\x4d\x20\xaa\xeb\x2a\x14\xa5\xab\x9b\x6a\x8f\xed\x3c\x6a\xb7\xb7\x1f\xef\x31\x95\xc0\xe8\x8f\xf5\x9f\x3c\xda\x63\x98\xdf\x8e\xf5\x36\x37\x13\xf0\xff\xa6\x83\x27\xdd\x76\x7b\x77\x07\x3b\x98\xd5\x6e\x90\x91\x69\x30\x9f\xfb\xf6\x8f\xf3\xd3\xb1\xb9\x47\x22\x81\x97\x00\x27\x82\x1d\x90\xd3\x63\xe2\xb0\xff\xe5\xc0\x26\x85\x63\xe2\xac\xff\x2f\x07\xb6\xf0\x17\x73\xa0\x6b\x5f\x31\x07\x7a\xf4\x8c\xc2\xb5\x60\xbf\x60\xd8\xb0\x11\xaf\x05\x48\x70\x1c\x9a\x40\xab\xae\x46\x91\xdd\x06\xae\x1a\xca\x33\xfd\xf6\x42\xa0\x7e\xdb\x4b\x60\x2a\x56\x24\xb7\x2c\x3e\x8f\x44\xe1\x7c\x05\x95\xa4\x80\x8b\x8f\x4d\x50\xb8\xf9\x5b\xb8\x77\x62\xc5\xd5\xac\x7b\xfe\xdb\xd0\xde\x37\x4f\x80\xef\x7b\x1a\xfc\x2b\x2b\x1d\xc7\x88\x7f\x37\x81\xdb\xa6\x6e\xd6\xc6\xe4\x46\xc0\x58\xc0\x3e\xb9\x13\x86\x1d\x5f\x19\xc3\xe9\x37\x72\xe8\x00\xe5\xe4\xbe\x60\x5c\xc2\x81\x60\xf5\x69\x09\x6a\xb6\xfa\x2d\xd9\x17\xc6\xc8\xc2\x7c\x0b\x85\xb3\xf9\x90\x28\xd8\xe8\xd1\xc1\x98\x4c\x05\xac\xf7\x60\x4c\x6e\xcd\x42\x09\x4a\x3d\x2c\xda\xa4\x83\x5b\x72\x2e\x60\xbd\x0b\x5d\x30\x23\xaa\xc6\x79\x62\x74\xa7\x51\x7c\xae\xcc\x8f\xab\x0e\xce\x8e\x51\x9e\xbd\x6a\x2b\x83\x7e\x67\xb1\xa9\xca\x9a\x65\x8d\xcc\xec\x3c\x6b\xa0\x9f\x03\x83\xd6\x85\x30\x46\x50\x75\xda\x4a\x66\x08\x85\xa3\xca\x42\x87\x85\xb1\x1a\x31\x09\xa3\x7a\x09\x6b\xe7\x27\x4a\x53\x3d\xf7\xaa\x36\x0a\xce\x0b\x7e\x7d\xce\xf5\x69\x6e\xae\x70\x34\x57\x8c\xa2\x3b\x22\xf8\xe5\x97\xb4\x61\xec\xb6\x32\xdf\x79\x5c\x30\x42\x84\xa1\xe7\x73\x0e\xb1\xeb\xd3\xc4\x96\xa5\x27\x3d\x6e\x50\x32\x86\xd3\x5a\x63\x82\x8c\xd2\xf5\x29\x04\x38\x27\x97\x8d\x84\x72\x4b\x8e\x04\x1c\xda\x8f\x25\x25\x14\x3e\x0a\x76\x29\xe0\xd5\x0a\xf2\xdd\x2c\x93\xef\xdb\xba\x6d\x51\x31\xd9\x72\x01\x90\x29\xf6\xa4\x8b\x29\x33\xd2\xc9\x2a\xc6\x6b\x9e\x08\x67\x31\x75\xf3\xa8\x63\xde\xb7\xd6\xd7\x98\xbc\x12\xa0\xc0\xa8\xe7\xc6\x00\x28\xdb\x62\x59\x4d\x16\x27\xe5\xb9\x5a\xef\x61\x92\x0c\x0a\x3f\x4b\xc4\xb0\xf2\xe3\x92\xb7\xe4\xad\x99\x84\x31\xc6\x3d\x26\xf0\x5b\xb0\x9f\x02\x8e\xff\xbe\xf5\xb9\xed\x14\x9d\xa0\xf0\x54\xb0\x63\x01\x9f\x56\xcc\x62\xb7\x3c\x8b\x27\x0d\x14\xfb\x49\xd8\x5c\x0f\x96\x6f\x19\xab\xad\xae\xe2\xba\x4c\xe0\x65\x5d\x81\x83\xbc\x38\x81\x5f\x82\xc5\x12\xde\x2f\xb3\x7b\x8e\x77\xb1\x02\xfc\xa8\x50\xc8\xd6\x5f\x8a\xd2\x19\xd2\x32\x7d\xdf\x90\x5f\x02\x78\xba\xff\x33\x86\x22\x31\xfb\x49\x85\xa0\x55\x41\x91\x87\x44\xd7\xf1\x86\x80\xa6\xbb\x3b\x4c\x37\x77\xbc\xb0\xaf\x91\xd5\x89\x62\x53\xc3\x97\xda\x19\x7a\x2f\xc8\x89\xf5\x66\xc3\xeb\xda\x95\xfa\x2d\xc8\x01\x39\x1d\x93\x8f\x02\x9e\x0a\xd2\x12\xa4\x4b\x29\x7c\x11\x64\x88\xb9\x6e\x8d\x42\xf0\x51\x40\x56\x7c\x85\x2f\xe1\x99\xa8\x61\x0d\xce\x3f\xff\xd8\xc9\x5c\xa8\x90\xaf\x41\x37\xc9\xc0\xfd\x05\x24\x1b\xbc\x90\x7f\x70\x8a\x9e\x99\x11\xbc\x13\xec\x2d\xbc\xa8\x1d\x67\xfe\x41\x0c\xf8\x2c\xd8\x3b\xf8\xde\xb8\x99\xe5\x5e\x6f\xa0\xbc\x5b\xf2\xd9\xcc\xf2\x0b\x81\x69\xd2\xd0\x28\xfa\x9b\x16\x5d\xd8\x48\x99\xc0\xd7\x4a\xf5\xd2\x71\xde\x0a\x1b\x8a\xff\x27\xdc\xcf\x47\x62\xa9\x32\x2e\x53\x69\x4c\x62\xb0\xd8\x9b\x2a\xa9\xa0\x01\x8d\x4e\x3d\x63\x36\x35\xec\x93\xaf\x96\x83\xd1\x04\x7e\x08\xb6\xf8\xc1\xb8\xf4\xf8\xbd\x19\xf3\x38\xc5\xfc\x8f\x58\x2f\xe3\x2b\x8c\xdd\x49\x6d\xc6\x14\x78\x23\xd8\x0f\x01\x32\x5e\xad\x9b\xa8\x86\xf2\x4c\x37\xd1\x75\xe5\x6b\xd2\x6d\x0d\xa4\x4d\xcf\xe9\xa9\x34\x4d\x27\x88\xb8\x56\x77\xc8\x98\x6f\x7a\xec\x4d\x14\x4d\x33\x95\x23\xaf\x5d\x96\x2b\x32\x97\x2b\xb9\xdc\xc1\x78\x61\x1f\xf3\x61\x05\x7d\xbc\x0c\x95\x4f\x0d\x8e\x1d\x9b\x04\x46\x9f\xc7\x4f\x52\x99\x27\x85\x69\x74\x34\x33\x86\x40\x68\xa6\x23\x8e\xff\x03\xdf\xd7\x3e\x11\xb1\xe5\x9f\xe9\x31\x12\xf0\xb8\x59\xb5\x89\xe3\x7a\x93\x6c\x4c\xde\x08\xd0\x31\x28\xe4\x09\x78\x55\x1b\x6f\xcf\x6c\x6c\x26\x10\xc6\x2c\x88\x21\x8a\x59\x18\xc3\xa8\x11\x36\x4a\xc3\x57\x3a\x93\x86\x7e\xed\x62\x54\x55\xde\x54\xd3\x9d\xd5\x56\x35\xb2\x2b\xe3\xe2\x4f\x2c\x17\xc7\x73\xf0\x9c\xdf\x32\x55\x49\x1a\xf5\xdf\xc0\x6c\xe7\xf3\xee\x9e\xd5\xd5\x6a\xf0\xf1\xe3\xb2\x9a\x9e\xa0\x3a\xc7\xff\x8f\xf9\xb3\x3d\x99\xb7\xe1\x82\x09\x4c\x70\xce\x1f\x25\x70\xdd\x34\xcd\xeb\xe8\xe1\x34\x2f\xdc\x56\x42\x61\xb8\x62\xa9\xaf\xe3\x6c\x2d\x5a\xf1\x8a\x73\x8b\x32\xcd\x87\x76\xf4\xf6\xde\xa5\xa1\xde\x43\x12\x9a\x89\xa1\x85\x52\x2d\xd2\x24\x11\x3c\xd3\x21\x35\x70\x2f\x4e\xf2\xca\x9b\x94\x5a\xcd\x43\x75\x7a\x86\xa6\x3b\x3d\x10\xac\x07\x31\x33\xa6\xad\xd9\x1d\x81\x0d\xd9\xb4\x95\xc2\x94\xec\x45\xa7\x52\xc5\x50\xf1\x55\xcc\xc6\x64\x14\x43\xf1\xcf\x53\x41\x02\x41\x81\x70\xcd\xee\xf9\x0b\x6f\x12\x43\x70\xe1\x91\x58\xb3\xfb\xe0\xc2\x9b\x09\x08\x6e\xbd\x28\x06\xff\xda\x9b\x89\x84\xba\xc1\x85\x79\x11\x6b\x37\xb8\x35\xef\x62\xed\xfa\xd7\x49\x0d\xb9\xe0\x88\xb9\x29\x2d\xf4\x73\x1c\x8c\x2a\x8d\x7c\x6d\x61\x99\xb9\x76\xf9\x8b\xcc\x37\xc3\x32\x65\xdd\x27\xad\xd8\x14\x05\x17\x60\x35\xf3\x54\x2d\xef\x61\xe6\x60\xb3\xfe\x78\x77\xb7\x54\x4d\x15\x24\xda\xa9\xd6\x02\xc1\x72\x76\xae\x17\xec\x86\x31\x19\xc6\x80\x48\x07\xb7\x4b\x14\x98\xa2\x96\xdb\x00\x02\x5d\x93\x14\x7e\x0b\x82\xfe\xb1\x3a\x23\xbc\xc4\xd5\xac\x18\x96\x86\x37\xcf\x62\xcc\x33\x0f\x13\x61\x04\x3e\x11\x9a\xfd\xcb\xf9\x17\x20\xa7\x40\xdf\xc9\x77\x41\x7a\x46\x40\x92\x1e\x35\x02\x86\x54\x54\x82\x6e\xa6\x2d\x08\x6d\xd5\x05\x1e\x83\xd0\xf0\x5a\xa0\x97\x96\xc2\x45\xcc\x48\x60\x0f\x4b\xba\x49\xdd\x7e\x3b\x24\x2f\xec\x3d\x6e\x4c\xa7\x35\xc8\xd4\xc4\x2e\x48\xea\x2d\x6e\x3a\x7b\x64\x36\xad\x6c\x86\x20\x93\x60\xe1\x2a\x09\x16\xfe\xe7\x96\x47\x00\x31\x0b\x50\x7a\xa5\xc2\xe1\x3f\x34\x3e\x96\x4c\x0e\x23\x2f\x62\xd7\x5a\x1b\xe7\x8d\x1b\x5a\x19\xdb\x78\x35\xf7\x3d\xcf\x77\xfc\x5d\xbc\xd2\x79\x6c\x6c\xdc\x18\x14\xfc\x4c\x95\xbc\x1b\x43\x4e\xe9\xbb\x31\xf9\x51\xcb\xff\x54\x4c\xd2\x33\xb1\xd8\x66\x59\xc2\x55\x2d\xd7\x2d\x44\x2e\xa6\x10\xc7\x6a\xd2\x68\x68\x06\xa3\x71\xbd\xc4\x4d\x5b\x64\x88\xfc\xa9\x6b\x61\x60\x8e\xc9\xa5\x40\x44\x2f\xd1\xec\x30\x7f\x34\x1e\xf9\xfc\x01\x21\x6c\x7c\x8c\x9a\xec\x19\xe2\x74\xdb\x34\x4b\x76\x21\xff\x66\x74\xfd\x3f\x4f\xe8\xdf\x8e\x2d\x9d\x56\xe0\x67\x38\x14\x9e\x4e\xdc\x7e\x05\xc9\xe5\x1c\x2f\x19\xf8\x69\x5c\x01\xbf\x70\xd7\x33\x0f\x38\x46\x15\xe0\x80\x9c\xca\x33\x0a\xfb\xe4\x2e\xce\x07\xbd\x78\xc3\xaf\x5a\xf1\xb6\x5c\x31\x3b\xe0\xcb\x6b\x5e\xa6\x83\xd5\xf6\x4f\x5c\x3c\x15\x30\x6e\xc9\x38\xce\x20\x50\xcc\xe3\x90\x24\x20\x1a\x97\xac\x95\x80\x4a\x97\xe9\xa0\x69\x99\xca\xa2\x8b\x97\x44\x57\xce\xc2\x79\x99\x85\xe3\x86\x7b\x45\x62\x4c\x58\xb0\x97\x39\x47\x8c\x3c\x8b\x51\x3e\xc7\x85\x5f\x04\x65\x9a\x91\xcf\x39\x98\x66\xb1\x56\x16\x67\xbc\x2a\xce\xd0\xa5\x12\xff\xa5\x1d\x7c\x43\x0e\x62\x2b\x0f\xca\x6a\x8b\x99\xa4\xc3\x98\x3d\x8b\xeb\xec\xa1\xb5\xd4\x63\x98\x7e\x8b\x0c\x7f\xa9\xd4\xd8\x82\xa3\x54\x7e\x3e\x15\xe4\xad\x4e\x0d\x2c\x12\x69\x76\xef\xf7\xbc\x13\x41\x48\x68\x7f\x3a\x89\x03\xc1\xa5\x77\x15\x43\xf0\xd4\x73\xc0\x81\xe0\xd0\x3b\x44\x29\xea\xdc\x3b\x10\xbc\xf3\xba\x09\x75\xfd\x1e\x35\x95\x42\xed\x06\x97\xa6\xde\x89\x20\xe6\xf7\x53\x6a\x6a\x9b\x5f\x87\xa6\x81\x7d\xeb\x5f\x53\xd3\xac\x86\x16\xe5\x22\x2d\x76\x17\x48\xae\xb7\x48\x59\x9b\x49\x82\x1d\xbd\xc3\x5d\x7f\x13\xc3\x7b\x41\x22\xdb\x05\x3e\x46\xd8\xf5\x0d\xd9\xcf\x4b\x7a\x34\x7d\x19\x21\xae\xf6\xad\x41\x34\x42\x30\x56\xf2\x50\x0a\x97\x8d\xb6\x42\x7a\x2a\x8c\x66\xc2\xc7\x3f\x58\x24\xaf\xfe\x60\x91\xbc\x8d\x9b\x5d\x9f\xd6\x41\x59\xf6\x4d\xfe\xac\xc5\xe9\x96\xbc\x8d\x2b\x8a\xac\xef\xd3\x04\x7e\x2f\x4b\x82\xdc\x77\x54\x93\x4c\x3f\x63\x36\xfd\x52\x4e\x44\xcd\xb2\xfc\x32\x1c\x1d\x45\x63\x8d\xf9\x51\xcb\xa7\xfb\xd9\x72\x64\xb7\x12\xca\xd5\x7f\xc7\xf6\x9e\x6e\xf9\x74\x9f\xc2\xf1\x32\x5e\x69\x5f\x24\x73\x60\xb6\x60\x88\x09\xa8\xbb\x66\xe0\x3d\x9b\xc0\x32\xff\xe4\xae\xdb\x1a\xe0\x37\x06\x7e\xc7\xa8\xf5\xb4\x28\x7e\x15\x46\xdb\x1c\x3b\x4f\x9b\x80\x8f\xc9\x71\x5c\xfd\x66\x79\x06\xe7\x85\x86\x9f\xb1\xfd\xac\xbd\x05\x84\x9f\x7b\xff\x64\xf6\xc6\x54\xc3\xd3\x98\x1c\xc5\x86\x18\x28\x9c\x34\x0b\x5e\x4b\x14\x36\x4e\x20\xa1\xf0\xbc\xa9\xe6\x3d\xdf\xf7\x30\x0e\xc1\xc6\x40\xf2\x96\x77\x8b\x21\x00\x31\xf9\x14\x53\x38\xd6\xa4\x45\x53\x0b\xed\x65\x85\x2e\x30\x46\x38\xbf\xfa\x01\x71\xf1\x51\xcd\x5a\x43\x4d\x81\x31\x9b\x20\xce\x4e\x23\x7f\xc5\x0d\x27\x36\xe9\x09\x99\x14\x37\x8e\x61\xbf\x2f\x63\x78\x1e\x57\x8e\xc9\xf0\x21\x88\xae\xae\x84\xc4\x03\x1d\x0a\xef\x63\x7b\xfe\x56\x67\xff\x90\x0b\x23\xa5\x2e\xb5\x51\xbc\x2e\x75\xfe\x1f\x6e\xcd\x37\x4b\xdd\x57\x8e\xe3\x28\x7c\xa9\x47\x32\x16\x14\x5e\xc7\x0c\xdf\x62\x8e\x66\x87\xc2\xbb\x98\x91\x91\x66\x28\xd4\x3e\x68\x18\x6a\x78\x1f\x9b\xe1\x7c\xd0\x70\xa5\xe1\x75\xf6\xfb\x5a\xc3\xaf\xec\x77\x4b\xc3\x97\xec\xf7\x44\x03\x17\xe9\xef\x99\x06\x91\xfd\xb6\x86\x55\xcd\xc0\xac\x7c\x4a\xe8\x59\xc9\x98\x54\xd5\xb3\xdf\x3a\x56\x41\x14\x4d\x60\x64\x8f\xfd\xe3\x34\xe8\xe7\xf3\x0a\x73\xec\x35\x48\x98\xda\x0f\x37\xc1\xf7\x55\xca\xd0\x7d\x30\xf2\x14\x04\xd2\x93\x10\x28\x4f\x43\xf0\x02\x33\xf0\xc1\x87\x98\xcd\x24\x7c\xad\x65\x12\x63\xf2\x21\x86\x7b\x7e\xe3\xad\xf7\x80\x6f\x79\xeb\xbd\x04\x7d\x3a\xdf\x62\xf6\xd0\xfd\x9f\x0f\xe1\x47\xcc\xae\x25\xbc\x69\xc4\xee\x80\x8c\xc9\x17\xdc\x40\x98\xcc\x9c\xd7\xf3\x46\xbf\xdd\x26\x0e\x7a\xe0\x5c\x3e\x9f\xe3\xf1\xad\xb1\x3e\xc6\xda\x1a\x2e\x1c\xad\x06\xea\x19\xc9\xcd\x57\xc7\x2e\xb4\xbc\x8d\x5e\xf9\xdc\x07\x86\x9e\x00\xe1\xa1\xc0\xd4\x4d\x6d\xc3\x11\xd9\xc0\x04\x1b\x6e\x6b\x3e\x37\x32\x3e\x7f\x23\xcc\x1b\x61\x90\x4a\x1f\x87\xf6\xc5\xb0\xf0\x87\xdf\x10\xc5\xa1\x00\x96\x66\x71\x12\xee\xb0\xef\x33\xe1\xe6\x79\x27\xb1\x5a\x17\xfd\x67\xc2\x0d\x00\x1f\x7b\xc0\x5d\x1f\xb8\x1b\x00\x77\x87\xc0\x5d\x41\xb3\xf7\x06\x9a\x8f\x7a\x5b\x76\xa0\x90\x3a\x7e\x20\x62\x46\x9b\x18\xb1\xd8\x7e\xd5\xa8\x82\xe5\x02\x4a\x01\x84\x90\x76\x6b\xb1\x8b\x28\x8c\xd2\x94\x19\x0b\x68\x99\xf2\xb4\xeb\x0c\x43\x61\x94\x16\x33\x82\x1c\x29\x4c\x24\x07\x23\x5c\x49\xc1\x6b\xe4\x4f\x4d\xc4\x5e\x0a\xdf\x54\x08\x62\x08\x62\x9a\xc7\x13\x71\xcc\x34\xe6\xdb\x6f\x58\xe3\x47\xb5\x87\x78\x12\xbd\x18\x27\x16\xd3\x45\x59\x73\x43\x34\x4f\xbd\x0c\xb7\x44\xd8\xc9\x0f\x28\x84\x8b\x7a\x26\xf6\x6d\xea\x29\xbc\x32\xb9\xa8\x02\x94\xc0\x04\x05\xa0\xd0\xb2\xbe\xb8\x6e\x7c\x16\xf5\xbc\xaa\xbd\x11\x53\xbb\x02\xd5\x65\xaf\x4e\xaa\x99\xd2\x84\x02\xe7\x8b\x61\x7c\x1b\x3d\x9b\x1d\xba\xdd\x4e\x7f\x0d\x4b\xbf\x85\x91\xb9\x59\x77\xe6\x11\x29\xd1\xfe\xe0\x85\xbd\x3d\xc4\x83\x7f\xd1\x0f\x70\x6e\x43\x9c\x5b\x1b\x2f\xe9\xe3\xdc\x56\xd1\xb2\x2a\x61\x90\x53\x09\x7e\x04\x26\x00\x85\x59\x29\xb2\x85\xef\xe2\xc2\x63\xc2\x94\x24\x4d\x34\x81\x1d\x71\xcc\x01\x10\x30\x8e\x1d\x71\xa4\x4d\x22\x18\xc7\x21\x0e\x29\x8c\x0c\xf1\x80\xcf\xf8\x9f\x36\xc1\x02\x16\xa9\xd1\x0a\x86\xce\x63\x83\x45\x54\xa1\xc0\x11\x22\x92\x1f\x0e\x42\xf0\x7f\x34\x8f\xc3\x6c\x1e\x87\xcb\xf3\x68\xa6\x01\x53\x57\xe1\x4e\xf6\x61\xc6\x0c\xd2\x13\xb3\xb7\xe1\x7a\x69\x6f\xf7\x70\x5a\x7c\x7b\x4d\x6f\x71\x46\xb5\xcd\x95\x90\xcf\x68\x9a\x21\x32\x9d\xd1\x72\xc3\x00\x3b\x0f\x59\xe0\x0e\x31\x61\x8e\x00\xbc\x71\x09\x18\xcd\x06\x33\x36\x42\x14\x46\x88\xc2\x68\x69\x66\x03\xd7\x87\xa0\x98\xd9\xd0\x2c\x8d\x1b\x40\x68\x40\x96\x76\xb2\xa1\xf9\x68\x09\x97\xf2\xac\x86\x7c\x85\x63\x2f\x9b\x3e\x6e\xa6\x8e\x9b\x69\xab\x06\x84\xda\x4b\xed\xad\x76\xdb\xfe\xe0\xe5\xb7\xc3\x74\xfe\xb3\xa7\xc2\xdc\x0c\xb8\x11\x7c\x98\xb2\xa0\x38\x43\xac\x7d\xa9\x92\xf2\xa8\x75\x85\x8b\x66\x24\x66\x70\x35\xe4\x89\xdc\x2a\xfa\x2b\x1a\x29\x79\xad\x70\x17\xf9\xb8\xfa\x41\x4e\xee\x71\x96\x1f\xbe\x70\xcd\xf0\xba\xc9\xb0\xae\x21\x9e\x1d\xbe\x60\x07\x61\x06\x3e\x62\x61\x79\xd5\x34\x87\xd0\xe5\xf9\x42\x45\x9c\x84\x66\xef\x44\xf9\x5a\x04\x71\x65\xb0\x29\x23\xe7\x78\x77\x8b\xfe\x45\x51\x10\x27\x30\x5a\x8e\xe3\xae\x89\xdb\x0d\xe2\x9a\x83\x70\x85\x99\xf1\x15\x8e\x5c\xd9\x91\xbf\xc2\x9b\x87\x7b\xdd\x62\x1e\x79\xb6\xd6\xe5\xe1\xdb\x0f\x03\xe2\xd4\x84\x66\x6a\xc2\xac\x2c\x32\x53\xa3\x8a\xa9\x89\xb2\xa9\x19\xb1\x68\x61\x6a\x22\xd7\xfc\xcf\x87\xc8\x0d\x60\x4c\x46\x86\xed\x46\xc8\x5a\x9a\xa6\xc7\x12\x69\x5a\x95\x2f\x4d\x51\x73\xf1\x98\xf8\xe6\x9d\x4f\xc2\x92\x30\x47\x6a\xc7\x23\x87\xfa\x09\xcc\x5c\x7b\xf7\x7f\x35\x6f\x87\xf6\x33\xf7\xe9\xfc\x94\xe9\xb1\xb2\x77\x90\x2d\xb5\x52\x85\xc3\xd2\x65\xb6\x2d\xd1\x46\x1a\x26\x09\xc9\xef\x30\x66\xb4\x35\xc0\xe9\xd2\x39\x1d\x71\x43\x07\x01\xa5\x5e\x79\x7e\x34\xcf\x87\x95\x4e\x41\x40\xcb\x13\x49\x61\xb6\x3c\xce\xcc\x0c\xc2\xfa\xaa\x90\x78\xda\xe0\xa8\x0b\x89\xa7\x17\x98\x61\x16\x94\x6f\x44\x8f\xb6\x12\x6f\xd2\x2c\x53\x15\x49\x4f\x1f\x74\x91\xf0\x51\x60\x22\xd6\x19\xc7\xb7\xde\x2d\x89\xcd\x2f\x81\x9f\x40\x49\x28\x5c\x57\xb7\x74\xf5\xdb\xd3\x43\x11\x44\x43\xf1\xf9\xe4\xd5\xb3\xe8\x6a\x1a\x49\xcc\x62\xd9\xf0\x15\x6a\x18\x36\x5e\x72\x38\xd2\x99\xf3\x76\x60\x35\x79\x2f\xf5\xa7\x65\x61\xdd\xad\xe6\xe9\x7a\x13\x83\xc3\x9c\x34\xdf\x9e\x36\x0a\xae\x36\x5a\x6d\xbb\xbd\x8e\x7f\x2b\xf1\x17\xa8\x0a\x5d\x73\x34\x21\xcb\x5e\xdf\xdc\xb4\x2e\x1f\x01\x5e\xf3\x52\xd2\xf7\x94\xd1\xe2\x61\xf1\x84\x03\x87\x21\xc7\x8f\x7a\x2c\x04\x1a\x5f\x35\xe0\x09\xa2\xce\x1c\xac\xf0\xf2\x3c\x45\x6c\xc6\x16\x95\xab\xf3\x10\xc2\x70\x64\xb5\x76\x6d\x14\x64\x6d\x47\x85\x59\x65\x6b\x82\x41\x8e\xb4\x0d\x07\x6e\x7a\x36\x6b\x41\xa4\x0d\xe4\x6d\x01\x11\xe9\x1c\x3e\x74\xcc\x6c\x8f\x8c\xe9\x40\x84\x99\x3f\x8c\x9f\x10\x2e\x1f\x08\xd7\xf7\x04\xa5\x60\xe6\x00\xaf\xb0\x07\xd7\xd4\x6d\x0d\xc2\xd8\xc3\x10\xdd\x16\x87\xd0\x6c\x75\x03\xa4\x6d\x3f\x08\x43\x0d\xa8\x63\x78\x6b\x2f\x9a\xc1\x05\xaf\x09\xb5\xcb\xa3\xfd\x3f\x69\x18\x93\x1f\x31\xf4\x00\x5f\x7d\x8b\xe1\x6b\x4c\x9c\x7f\xfe\x19\xa0\xd1\x29\x5d\x7e\x4c\xed\xb1\x9f\x3f\x38\x26\xa9\x3f\xdf\x06\x9d\x8e\xc9\xe7\x18\x0d\x75\xb4\x59\x2e\x35\xf5\x8e\x89\x19\xc7\xa5\xa6\x60\x86\x75\xc5\xe1\x5d\x0c\x27\x44\xc2\x3d\x3f\xf6\x2e\x35\xf0\x91\x87\x69\x17\xaf\x3d\xed\xfa\x49\x75\x03\xbc\x88\x3d\xe1\xf2\x04\xa6\x3c\xbd\x29\x74\xce\xb3\x30\xb9\x1b\xfb\x6b\x27\x81\xbb\xba\x91\x5c\xa0\xfc\x59\xca\x0f\x91\xe5\x5b\xb0\xdf\xa8\xe6\x78\x27\xa2\x7a\x6d\xdc\x98\xb3\x95\x82\xcd\xa2\xe0\x71\xa5\x60\xab\x28\x78\x52\x29\xe8\x16\x05\x3b\x95\x82\xec\x33\xba\x6b\xe7\x7c\xe1\xfb\xb5\x37\x7c\x51\x3f\x9f\xf2\x24\x81\x71\x9d\xc5\x58\xba\xa1\x75\xdb\x50\x9e\xdd\xd0\xda\x6f\x28\xcf\xfc\x6c\x07\x0d\xe5\xd9\x0d\xae\x67\x38\xc9\x9b\x09\x1c\xf2\x55\x86\xf5\x42\xb4\xa1\xb1\x3a\x8d\x15\x71\xc4\x99\x94\x70\xd9\xc8\x61\x84\xb1\xf5\x1f\x0a\x69\x2f\x67\x7c\xac\xb7\x8e\x13\x78\xc5\xd9\x11\x27\x63\x72\xc9\x61\x13\xb6\x36\x29\x85\xb7\xf8\x55\x8b\x9f\x9c\xed\x93\x43\xa3\xee\xbc\xe2\xf0\xd6\xfc\x47\xe1\x37\x67\xd7\x70\xbc\xdc\x63\xd9\xa3\x6d\x18\xd4\x6f\x0e\x5b\x9b\x20\xed\xc7\xba\x8c\xc4\x42\xde\x96\x0e\x44\x1b\x92\x4b\x3f\xb5\x2a\x8a\xcb\x20\x78\x38\xd1\x97\x4c\x80\xb2\x2e\xe8\xa7\x0d\xf6\x3c\x4f\xe0\xd3\x9f\x50\x38\xe2\x44\x3d\xdc\xda\xcc\x39\x9e\x2e\x4e\xc8\x32\xdc\x5c\xde\x97\x66\x47\x1a\xc6\xdf\xa2\xa0\x18\x86\x71\x9e\x70\xa6\x24\x3c\x6f\x9c\xd4\xee\xde\x2b\x7c\x1e\x48\xcf\x30\xbf\x97\x9c\xfd\x80\x5f\x0d\x88\x66\x21\x3c\xef\x6b\x05\xbc\xd1\xd8\x53\x6c\xb7\x36\x1f\x28\x57\x80\x60\x27\xe9\x42\x6c\x6d\x82\xde\xe8\xe1\xa7\x39\xe4\xe0\x8b\x61\x66\xe7\xd4\x53\xee\x39\xde\x90\xf9\xc4\x8d\xd5\xe9\x16\x8c\x1a\x97\xe9\x17\x27\xca\x1d\xd1\x8e\xe1\x2c\xcf\x39\xec\x80\x78\xf0\x8a\x53\x30\xac\xa3\x50\x68\xca\x35\xd3\x65\xc5\x62\x0a\x5f\x38\x1b\xc1\xeb\x26\x1f\x46\x89\x67\xab\xbd\x6e\x31\x97\xef\x39\xac\xf7\xe0\xfe\x1c\xdd\x20\xfa\xe1\xd6\xe6\xbc\x0b\x23\x2f\x4b\x44\x6e\x59\x08\x70\xef\x96\x7c\xc1\x31\x61\xac\x5c\x1a\xe1\xa7\x36\xcc\x20\xf1\xd8\x01\x89\x83\x83\xa0\xd9\xe1\xc3\xbb\xda\x09\xeb\xee\xc9\xdc\x2b\xfb\x5f\x5b\x9b\x78\xd2\xfc\xc5\x68\x1d\x72\x43\x97\x7c\xa8\x37\xe4\x35\xde\x1a\xdc\xd0\xa6\x07\x09\x2d\x10\xf9\xf8\x7f\xf2\x84\xc2\x8b\xba\xe5\x5a\x97\x6e\x2b\x81\xcf\x4d\xeb\x9e\x6d\xfa\x2c\x7e\xef\xfb\x8a\x8a\x95\x40\xbf\x0f\x2b\x2a\x56\xc2\x82\xbf\xfe\x81\x17\x7d\xe3\xec\x39\xfc\xa8\xa5\x34\xbc\x5e\xd4\xe4\x05\xee\xf4\x12\x8a\xa7\xcf\x09\xbc\xe1\xec\x1c\xe4\xe2\x77\x62\x16\xee\x67\xf5\xf6\x98\xa5\xf0\x42\xf7\x2a\x3c\xbc\x6a\xa3\x87\x24\x88\x37\x5b\x74\xbe\x5b\x41\x33\x6e\xc6\xa0\x82\xe6\x73\x5e\x19\xa0\xea\xdb\x32\xc4\xa6\x57\xd4\x7b\xc3\xf1\x70\x54\x05\xd0\x85\x1f\x46\x95\xdf\xe8\xa5\x21\x6d\x22\x60\x2f\x20\x0e\x6a\xf7\x5a\xc7\x71\x12\xe0\xc1\x7f\x10\xaa\x6f\x84\xe9\x52\xbc\xfe\x31\xf9\x44\xe4\x69\xf7\xcc\xc8\x60\xfb\xa9\x9a\x1e\x35\x12\xd6\xbe\xed\xc8\xd3\x5e\xa9\x68\x93\xa2\x04\x4e\x20\xa8\xc5\xc9\x4a\xea\x7f\xe4\xda\xda\xda\x9a\x93\xea\x0a\xff\x48\xa3\xb5\xd1\x04\xc2\x80\x1d\x4a\x88\x9a\xe6\xc1\xf9\x47\xfe\x23\x89\xd3\x89\x03\x22\x3b\x3d\xda\x71\xe8\x9a\xd3\x09\x02\x32\x0a\x52\x4f\xec\xa8\xa1\x4b\x3f\x40\x6e\x96\x80\xbf\x0c\x7a\xd5\x41\x4b\xe6\x28\x28\x6c\xd3\xd2\xd1\xa6\xbd\x53\xcd\x03\x12\xe7\xfc\x54\x96\xbf\x82\x6c\x63\x81\x8a\x34\xff\x99\xff\x8f\x8c\x04\x51\x46\x7f\xb3\xa1\x53\x8a\xd2\x76\x7b\x4c\x44\x00\x7e\x6c\xf6\x24\xc1\x94\xd0\x10\x58\x7a\x12\x03\xc7\x75\x3a\xb1\xe7\x9c\xfe\x0b\xbf\x76\xfe\xaf\x33\xc7\xde\x02\xc4\x40\xb3\x9a\xbb\x9b\xf6\x1c\xc8\xda\x3b\xce\xa9\x9d\x2b\x97\xd3\x8e\x73\xe6\xf4\x4b\x70\xc3\x55\x50\x36\xbd\x34\xce\xdb\xe5\xf6\x6e\x8a\xd5\x3b\xa3\x42\x87\x1e\x31\xa3\x49\x0e\x9c\x4f\x17\x62\xed\xf5\x2c\x92\xee\x73\xd4\xfe\xdd\x48\x8a\xe3\xd1\x1a\xd7\x6b\x97\xb3\x48\x3a\x9d\x4c\x2d\xfb\x82\x37\xa0\x3c\x67\xa9\xaa\x43\x3b\xce\xda\x88\x87\x13\xfc\xa6\xfb\x9a\xbe\x10\x6b\xa3\x68\x32\x89\x6e\xec\xb7\xa8\xe3\x80\xfc\xe0\x24\xa2\xa6\xd6\x0d\xbf\x9b\x79\x4e\x7f\x81\x8c\x0c\xe9\xe0\x80\x46\x30\x26\x3a\x80\x28\x80\xc8\xa8\x9a\x92\x71\xa6\x59\x84\xa7\x5b\x01\x53\xcb\xca\xb1\x73\xc2\xe5\x5a\x28\x75\xb4\xc6\x6b\x46\x80\x9f\xc7\x97\xd1\xda\x34\x9a\xcd\x42\x3f\x9c\x84\x3a\x14\x33\xa7\x63\x07\xdd\x3c\xbe\x75\x87\x56\x4e\xd9\x7c\x5c\xfc\x19\x2e\x49\xb6\xf8\xa8\xbe\x3a\xef\x55\xe4\x4f\xc4\x95\xed\xc8\x0c\x1b\xd3\xef\x34\x41\xee\x38\x9e\x19\x2a\xee\x19\x6f\xb9\xed\x79\x78\x2d\xa4\x85\x80\xf5\x1c\xda\x21\x41\x40\xc6\x24\x0c\x60\x1b\x66\xa6\x7d\xfa\xda\x37\xfc\x68\x16\xb0\xa9\x84\x49\xc0\x66\x01\x79\xa9\x29\x5c\x07\x6c\x28\x61\x58\xc7\x01\xf3\xd9\x9e\x04\x30\x26\xd7\x01\x94\xae\x65\x37\xd7\xbf\xe7\x53\x4f\x03\xff\x61\xd8\xf8\xc8\xf2\xf1\xab\x80\x5d\x49\xb8\x08\xd8\x8d\x84\x69\xdd\x2e\x2d\xe9\x87\xe7\x0d\xe5\x4f\x20\xc0\xf2\x9b\xa6\xf6\x3b\x70\x8e\x15\xee\x1a\x2a\x64\x07\xb9\xe3\xc0\x88\xe0\x9d\x04\x6e\x2b\x63\xa8\x7e\x16\x67\x4c\xae\x82\x9a\xf0\xaa\x31\xb9\x08\x20\x86\xa5\x48\xd9\xbb\x80\x04\xd5\xd8\x22\xac\x79\x13\x90\x03\x72\xca\xe1\xdc\x14\x9f\x19\xf3\xa5\x62\x6a\x4c\x91\x79\xe1\x17\xfc\xbd\x3b\xfb\xc3\xa0\x87\x91\x22\xc1\xaa\x10\x1b\x5c\x91\x5b\x72\x9b\x2f\xcb\x38\xa0\xb8\x04\xf6\xda\xff\xc1\xaa\xc5\xf9\xea\x69\xf0\x63\x4f\x81\x9f\x5e\x32\x7d\x16\xa4\x86\xce\xa1\xe1\x0e\x0b\xc3\xae\x1e\xf7\x3b\xb1\x9c\xaa\x28\x10\xb3\x99\x18\x3a\x5e\x31\xf6\xae\x3d\x08\xc8\xee\xcf\x95\x4a\x7a\x69\xc9\x2c\x9e\x4e\xd5\x52\xbb\xcd\xa5\x23\x82\x69\x40\x9c\xcf\x72\x2c\xa3\x1b\xb9\xa6\xef\xa6\xc2\x5b\x73\x3a\x18\x38\xf1\x2c\xa0\x70\xd4\xb0\xb2\x8f\xc0\xb7\x17\xf6\x03\x76\x4b\x86\x01\x14\x17\xfb\x9e\xde\x39\x70\x14\x10\xd3\xd8\x96\x64\x57\x00\x97\x0b\x34\xd7\xc2\x81\xc3\x00\xee\x02\x72\x10\xe0\x09\xea\xc7\x80\x45\x0d\x2e\x59\xfc\x24\x50\x3e\xa7\xbf\x0c\xc1\x1f\x78\x21\xf0\xd7\x5e\x0c\xfc\xbd\xa7\x52\xfa\xbf\xf0\x04\xf8\x37\x1e\x07\xff\xce\x8b\xc0\x7f\xee\x61\x38\xe4\xab\x0c\x4f\xc9\xaf\x84\x03\xcf\xb0\xcf\x9a\x91\xf1\x6d\x5c\x21\x0a\x6f\x03\x36\x8d\xe1\x67\xc0\xde\x0b\xf8\x5d\x2b\xe5\x7e\x9a\x0d\x9f\x85\xd8\x3e\xb6\x21\xb6\x34\x81\xe3\x80\x69\x09\x4f\x83\x45\x67\xac\xfd\x2a\x66\x96\xaa\xf5\xe1\xe9\x3f\xb3\x5b\x3f\x3a\x7b\xe8\x6a\x31\x43\xc7\x4d\xee\x22\x48\xb3\x4d\x75\x64\x91\x6d\x81\x59\x35\xc1\x8a\xf9\x4f\x01\x7b\x16\xc3\x49\x2d\x4e\xf8\x19\xf3\x9e\xd5\xd5\xea\xe3\x94\x2b\x91\x7f\x46\x88\xdb\xee\x12\x78\x6e\x48\xf1\x6d\x95\x14\xc3\x11\x79\xb2\xf7\x42\x94\xd0\x3b\x09\x88\x73\x70\x3b\x15\x81\x16\x43\xc3\x3c\xaf\xa2\x99\x5e\x7b\xb2\x36\x0c\xcf\x43\x3d\x83\x35\x3f\xd6\x6b\xe7\x91\xb6\x92\xc4\x36\xa4\xe9\x78\x9e\x06\xc4\xe9\xba\x86\xb4\xf2\x71\xb9\xad\xc1\x49\x40\xfe\xf5\x4a\x5e\xf3\x49\x38\x5c\x1b\x4d\x22\xae\xbd\x35\xe7\x5f\x1d\xd9\xf9\x97\xf3\x2f\xea\x3d\x15\xe4\x38\x20\x3d\xb1\xf5\xc0\x3a\xa3\xe0\x9b\x20\x9f\x02\x12\x61\x40\xe5\xcb\x80\xbd\xd5\xf0\x2b\x60\x7f\xf8\x88\xd7\x4b\xa3\xbb\xec\x76\x1f\xa8\x07\xbb\xdd\x07\x3d\xb1\x65\x7e\x13\xbd\xc1\x29\x3e\x18\xe0\xa2\x13\x9b\x2d\xfc\x3e\x68\xf8\xb2\x40\x17\x75\x8a\x8a\xfa\x06\x82\x6d\x6f\x61\xb6\xee\xed\x1d\xc6\xf4\xa0\xe7\x75\x21\x66\xa2\x1f\x17\x19\xf8\x3a\x9d\x22\xe5\x6c\xb9\x71\x9c\xe6\xf8\xdc\x7e\x3c\x9f\xef\x3c\xda\xe3\xa5\x85\x57\xac\xd7\x7d\xa0\x3a\x7c\x63\xfb\x71\x9e\xbe\x13\x3f\xdc\x82\x31\x35\xb6\xa7\x0d\xe5\x29\x9a\xc0\x97\x12\xb2\x65\xb1\xb1\xbc\x80\x36\x10\xd4\xf0\xc1\x8c\xa3\xbe\x0f\x48\xf3\x22\x84\x52\x8b\x73\xa1\x16\x96\x41\x95\xb2\x6d\x54\x48\x00\x17\x5a\x1b\x75\x61\x15\x09\x54\x56\x2e\x81\xd7\xb5\xb4\x6b\xe0\x66\x58\x0c\xf9\x9d\x67\x21\xa0\x9a\xfa\x2e\x60\x6f\xe0\x45\x5d\xab\xf5\x31\x79\x67\x64\xae\xa4\xed\x36\xc1\xdf\xbd\xae\xb1\x32\xe6\xf3\xb4\x04\x9f\x68\x02\x9f\x6b\x95\xf2\x8d\x2c\xf9\x3f\x51\x0f\xb7\xe7\x5d\xba\x41\xd4\xc3\x5e\xb7\x3b\xef\xd2\x8e\x79\x83\xbf\x12\xf8\x5e\xb3\x35\xb2\x98\x1e\x5e\x3e\x11\xb3\x2b\x9b\x1b\xa6\xaf\x03\xc2\x33\xf2\x5f\xee\x7c\xab\xb7\xb3\xb5\x2b\x76\x1f\x10\xb1\xd1\x7b\xf2\xa8\x4b\x41\xb3\xc7\xbb\xdb\x62\xe7\x01\x21\xf1\xde\xd6\x7c\xbe\xfe\x22\x20\x82\x0e\xf8\x46\xcf\xe3\xb4\x43\x3e\x9b\xa7\x8d\xcf\x01\xc1\xca\x85\x03\xed\xa9\x20\xb2\xa3\x3a\x9a\x26\x99\x1f\x2c\xce\xbf\xdd\x9a\x56\xd9\xea\xed\xf1\x01\x22\xe3\xa9\x4c\x70\x14\xf9\x42\x37\x9f\xec\xf1\xf9\x7c\xf3\x09\x63\x8c\xb7\xdb\x69\xaf\x59\xed\xcd\xdd\x47\x8f\xb7\xc5\x0e\x5d\xc8\x54\x5a\x81\xb8\xd3\x7d\xf2\x68\x37\xaf\x93\xe7\x3a\xdd\xea\x96\xea\x3c\x7a\xf4\x68\x57\xec\x2e\xe6\x6e\xac\x80\xe9\x75\xb7\x76\x1f\xe7\x75\x76\x6b\xc1\xf4\xb6\xba\xdb\xbb\x05\x3e\x8f\xea\x01\xed\xec\x6e\x95\x90\x7e\x5c\x5f\xe9\xf1\x56\x6f\xf7\x71\x5e\xe9\x49\x6d\x77\x9b\xdd\x27\x4f\x76\x36\xf3\x4a\xbd\x6e\x2d\xa8\xcd\xad\x9d\xc7\x8f\x4a\xb5\x7a\xf5\xb0\x76\x37\x77\x77\x8a\x69\xea\x6d\xd6\xc3\x7a\xfc\x78\xc7\x4e\xe6\x82\x94\x2e\xef\xd1\xab\x48\xea\x0b\xdc\xa1\xb1\x31\x86\x70\x97\x1a\x2d\x6b\x29\xde\xbf\x51\xbf\x7c\x4a\xb2\x8f\x34\xa6\xa1\x8d\x5f\x02\xb2\x4d\xe1\x77\x40\x9c\x0d\x87\x96\x5e\x6e\x96\x5f\xe2\x33\xa5\xf0\x61\x85\xe6\x2a\x1f\x10\xc3\x6c\x3b\xa8\xb2\x7e\xad\xd9\x38\x69\xbd\xec\x82\x5c\x05\xe5\xf2\x3f\x36\x0e\xfe\x17\x72\x00\xc4\xe1\x93\xb3\x8c\x97\x57\x87\xac\x57\x42\x16\x2a\xfd\x58\x98\x6f\xb5\xad\xe7\x62\x0e\x82\x80\xda\x78\xfb\x33\x5a\xaa\xfd\xa6\x2e\xa6\xb6\x9b\x60\xb3\x1f\x16\x8f\xc5\xb9\xfe\x10\xfc\xa1\x79\xcf\x36\xef\xd8\xe6\x75\x55\x36\xd2\x2a\x66\xb6\xcf\xfe\x30\xb0\xa2\xfc\xa9\x20\x13\xf2\xcb\xa8\xa4\xdd\xec\xff\x6d\x98\x26\x5e\xee\xfb\x1e\x50\xf8\xd6\x60\xa5\x3f\x8d\xe1\x6b\x60\x6f\xaf\xd5\xe8\xa1\x96\x4b\x7d\x5b\x14\x16\xd3\x0a\x9b\xd6\xa9\xba\x68\x94\x69\x14\x12\xa8\x35\xbe\xa9\xed\x70\x95\x7f\xc8\x9e\x7c\xb9\xf6\xde\x11\xba\x59\xc2\x18\x31\x93\x61\x83\xed\xb1\x99\x6a\xa0\x2a\x64\x17\x12\x74\x5d\xb5\x35\xfc\x46\xe1\x9b\x00\x64\x68\xe5\x88\xa8\xad\x65\x4d\x86\xf3\x80\x5c\x62\xa0\xaf\x0a\xe1\x48\xdb\xc8\xfb\x04\xe2\x90\x15\xca\x6a\x3c\x73\xe0\x32\x48\xb5\x57\x21\x87\xb3\x7d\xed\xc0\x8f\xec\x45\x3c\x35\xd3\x31\xac\xbc\x9b\x69\xae\x74\xb5\xda\x28\x94\xe7\x42\x4d\x55\x28\x35\xea\xa1\xf6\x6d\x96\x37\x63\x86\x3a\xf2\xab\x5c\x47\xe6\x52\x46\x1a\x13\x62\xce\x1c\xd0\x21\x6a\xcf\xfb\x64\x3f\x00\xe7\x5c\x48\xa1\xb8\x8e\xd4\xe7\x93\xb7\x0e\x08\x5b\x74\xa9\xd3\x76\x13\xee\x8b\x49\xd1\xe4\x2e\x20\x1f\x03\x9a\xff\x1f\xf0\x6c\x58\x69\xfe\x0f\xd3\x69\x1c\xd2\x05\x64\x1c\x78\x15\x34\xc2\x6b\x59\x85\x3d\xa8\x9b\x52\xeb\xc5\x0c\xc3\x55\x31\xa1\x1f\x63\x24\x18\xef\x55\x5c\xca\x21\x15\x35\x35\xc9\x4e\x2b\x32\x37\xe5\xa8\x81\x2c\xb2\x23\x11\xbf\xa1\x3c\xb3\x48\x67\x61\x7a\xe4\x31\x09\xd3\xe0\xc3\xeb\x5a\xda\x48\x9d\x4c\x09\x0c\x1b\x01\xfa\x9e\xa3\xc5\xad\x76\xb2\x74\x78\x21\x3b\x97\x70\x15\x1a\xed\xf4\x22\x5c\x7d\x8f\xe4\x2a\x24\xf7\xfe\x07\x63\xb0\x6c\x7b\x84\xb3\x18\x86\x21\xa9\xb3\x80\x5b\xa1\xbd\x91\xf7\xa1\x72\x28\x9a\xce\xe2\x28\xfd\x7e\xb6\x99\x49\x1b\x63\x4b\x21\x08\x3c\x05\xc1\xd4\x93\x10\xbc\xf1\x2e\x35\x04\xef\x3d\x0d\xc1\x89\xb7\xde\xcb\x7c\xe2\x09\x85\x69\x98\x26\x73\x38\x6f\x5c\xa8\x1b\x72\x11\x82\xf3\xe2\xe0\x93\x03\x2d\x90\x30\x0d\xed\xde\xbc\x09\x6d\x00\x70\x2b\x24\x68\x0d\x3b\x42\xa9\x48\x19\x72\xa6\x36\x1c\xf8\xae\x61\xb6\x32\x2f\xf2\xf8\x0f\xcb\x77\x1b\xae\x90\x30\x44\xa5\x49\xfe\xf6\x43\x76\x2c\xe1\x20\x64\x6f\x25\x3c\x0b\xd9\x41\x68\x34\xf3\xc3\xb0\x29\xa9\xe6\x98\xec\x87\xb5\x11\xac\x21\xb1\xf7\x36\x6d\xe6\xa8\xa3\x4a\xdf\xf6\xda\x4c\x3d\x08\xf5\x37\xa0\xc7\x24\x4d\xa9\x96\x80\xc8\xba\xb8\x0c\xd9\x57\x09\x1f\x97\xa7\x3d\x75\x67\x64\xab\xfc\x5c\x12\x84\x7c\x19\xa6\x1a\xbc\xb1\x64\x17\xa7\xa6\x84\xc4\x61\x58\x2f\xb6\x48\x9a\xdc\xe9\x63\x68\xd3\x64\xd9\x04\x4f\x47\x21\x19\x6b\x0a\x07\x21\x69\x21\xf0\x22\x57\xd2\xdb\x4a\x1f\xe5\xd1\x74\x0d\x0a\x3f\x1b\xe9\x05\x51\xb0\x97\xa8\xfa\xdf\xa5\xfb\x89\xcf\xc6\xec\xde\xf7\x9e\x85\x10\x78\xaf\x42\x18\x7a\x6f\x43\x10\xde\xcf\x10\x46\x9e\xaf\xad\xe9\xf9\x3b\x84\xe3\x10\x9e\x86\xec\x9b\x24\x8e\x69\xe0\x50\xf8\x14\xb2\xa7\x12\x4e\x1a\xbb\x79\x6a\xa6\xf5\x53\x68\xcc\xd8\xf4\x9f\x83\x10\x24\x85\x8f\x18\xc5\xbc\xbf\x5c\xf0\x2a\xa6\x36\x81\x19\x85\xe7\x2b\x90\x3f\x09\xd1\xe9\xff\xc2\x10\xdc\x25\x4e\x77\x5d\xb2\x8e\x94\x27\x0c\xee\xaa\x9b\x75\xc9\x9d\x9d\xe9\x81\x4e\x9a\x88\x79\x4d\xdc\x06\x42\x0c\xc5\xd0\xa9\x6a\xe0\xce\x91\xd0\x37\x91\x1a\xaf\xd9\x5d\xb4\xa0\x6a\xe3\xc9\x7c\x1c\x10\x82\xc1\x09\xd4\xf5\xef\x5c\xff\x2b\xc5\xcf\xc1\x2a\xf3\x10\x44\x70\x13\xda\x34\xd4\xb9\x06\x9e\x1d\x39\x64\x4e\x50\xe7\xb3\x14\x99\xc5\xa6\xc4\x6c\x1a\xc9\x99\x58\x1b\xa9\xe8\x6a\x8d\x4f\x43\x14\xe0\xee\xe2\xc9\xb4\xf3\x8e\x4f\x46\x91\xba\x12\xc3\xb5\x58\x4d\xd2\x3a\x49\x82\xbe\x6d\xea\x8d\x43\x7b\xc5\x83\xc2\xcb\x5a\xb6\x29\x07\x8e\x56\xb1\x70\xbc\x34\x75\x5f\x02\xbf\xea\xeb\xb9\xad\xf9\x3c\x0b\x8a\x1e\x48\xf4\x6f\xbc\xaf\xad\x29\x64\x4d\xb4\x4b\x02\x5f\x6a\x2b\x67\xe9\x03\xdf\x87\xf0\x8d\x13\xd9\x71\x98\x63\x0d\xcf\xf0\x7f\x27\xc1\x9c\xe9\x69\x90\x45\xc5\x50\x3c\x6f\x4d\x93\xcc\xbd\x6b\x18\x94\x9f\xc0\x8b\xb0\xf6\x10\xc8\x3f\x2c\x3e\x9a\x18\x8c\x3b\x24\xbb\xf0\x80\xb1\x18\x4f\x39\x7c\x34\x98\xbf\x0e\xed\x0d\xd1\x77\x21\x48\x41\xa4\xfb\x8d\x52\x7b\x8b\xd4\xaa\xfa\x1d\x65\xfe\x24\xf0\xb9\x8e\x49\xa6\x76\x29\x51\x15\xb7\xa7\xb6\x51\x3d\x79\x60\xd1\xf7\xc6\x4d\x80\x13\xf1\x19\xf9\x44\x2b\x4d\xe1\xd0\x58\xf7\x98\x64\x69\x1b\x1a\x06\x3b\x42\xcf\xc9\x7b\x0c\x31\x3c\x46\x43\xf9\xc8\x1a\xca\xaf\x31\xc6\xf0\x2b\x84\xcb\xe7\x3b\x9f\xe2\x7c\x52\x38\x45\x5f\x89\x5c\x4c\xd5\xb5\x70\xe7\xf6\x85\xb6\xd3\xf5\x22\x9d\xb6\x23\x0d\x1f\xc2\xca\xf5\x09\x85\xa7\x3c\x11\x1b\x93\xef\xb5\x6c\x7a\x4c\xbe\x84\x99\xf6\x49\x13\x78\x49\x42\xb0\xc9\xa3\xf2\xf4\x65\x70\xa4\xc9\xcb\xd0\x62\xb6\xde\x03\x9b\xf0\xec\xb8\x9c\xcf\x6c\xa1\x86\xc8\x6a\xa4\x0e\xda\x4a\x71\xd7\xde\xe2\x33\xc5\x85\xae\xf5\x2b\xc4\xdc\x1d\xc7\x59\xe6\x35\x40\xff\x75\xbe\x8c\xdd\x3d\x3c\x99\x19\x38\x83\xec\xb0\xa2\xed\x40\x44\x3d\xc7\x49\xe0\x5b\x93\x24\xb1\x15\x1f\x3a\x78\x8b\xb0\xd0\xf6\x6c\x0f\x33\xa7\xf3\xd5\xf4\x79\x56\x74\xf2\xdc\x60\x78\x1e\x82\x36\x0a\x21\x0f\x2d\xc7\xfc\xf1\x9f\x41\x5f\x0d\x34\x4e\x81\xbe\xf9\x83\x82\x26\xa3\x06\x0d\x22\xab\xa0\xa2\x65\x9a\xb3\xa7\x86\x23\xa4\x37\x6e\x63\x5a\x8f\x91\xe0\x8e\x90\xde\x82\xd7\xf8\x21\x85\xaf\x7f\x4f\x09\xab\xa9\x40\xba\xef\xff\x48\x07\xf1\x6a\x3a\xe0\x59\x71\x4a\xad\x86\x0a\x82\x1a\xca\xd0\x15\xca\x08\xf1\x61\x31\x23\x1f\x51\x4c\x00\x7a\x8a\x2d\xf3\xc5\xb8\xac\xf2\x42\xac\x22\x21\x1d\xfd\xef\xb0\x46\x8c\xc8\xc3\xdc\x9b\xb8\xf3\x0c\xdf\x45\x67\xb6\x7d\x3c\xd6\xc4\xc6\x14\x52\x38\xd2\x94\x96\xed\x3a\x0a\x22\x4a\xb5\xcf\x38\x4a\x35\x70\xde\xb0\xe4\xd9\x31\x55\xd0\x50\x9e\x51\x44\xd8\x50\x9e\x85\x39\x45\x0d\xe5\x59\xa2\xea\x51\x43\x79\x6e\x53\x44\xec\x48\xc2\x2c\x62\x42\x11\x67\x2a\xd4\x2c\x9c\x69\x9c\xfd\x83\xdb\x29\x97\xc3\xfd\xc9\xc4\x01\x3f\xa2\x30\x89\x9a\x18\xe6\x09\x51\x70\xcf\x5b\x5e\x1e\x80\x77\x12\xc3\xa7\x18\x0c\x65\xa6\x69\x43\xae\xeb\x70\x30\x12\x65\xe0\xdc\x67\x8b\x06\x78\x8e\xff\x02\x19\x9e\xa4\xb4\xe3\x24\x0e\x2e\x61\x0b\x27\x72\x3b\x81\xab\x08\x8d\x8f\xa8\x36\xfe\x56\x32\x33\x96\x69\x23\x8e\xa8\x5b\xa5\x5a\x1c\x66\xd2\xae\x82\x69\xbe\x1d\xb9\x7c\x1d\x75\xc1\xcf\xb8\xe8\xd2\xda\x4a\x12\xb8\x89\xd8\x77\xb8\x8b\xd8\x57\x18\x37\x62\x24\xf7\x7a\x03\xc7\xc9\x52\x05\xa5\x22\xe7\x36\x62\x9f\x61\x3f\xfa\x83\xf7\xff\x9e\x1f\x7b\x1c\xf8\x67\x4f\x01\x1f\x19\x3b\x8b\x7b\x1a\x7c\x61\xec\xa2\x6b\x7b\x5f\xea\x20\x6a\xbe\x2f\xf5\x52\x90\x98\xce\xe7\x63\x72\x1b\x81\xf3\xff\x71\xcc\x5e\xae\x9e\xd2\x70\x36\x26\x77\x11\x38\x9e\x93\x26\xfc\xe0\xe9\xc9\x3d\xc7\x93\xfb\x6a\xe5\x2c\xb5\xef\xfb\x80\x8c\xc9\x77\x01\x41\x07\xb9\x43\x16\xca\x10\x2e\x25\x97\x8e\x58\x98\xed\xdc\x23\x4d\x26\x64\x3f\x42\xed\x74\x1c\xd9\xaf\xd1\x45\xe9\x09\x65\x39\xda\x34\xad\x14\xc3\xa5\xce\x4b\x29\x3c\x8b\x9a\xf2\x11\xbf\x14\x44\x2c\x0e\x2a\x4e\x07\xf5\xd0\x81\x2c\x7b\x8f\x5f\x93\x9c\xe1\x86\x1c\x58\x7c\xbe\x0b\x1b\x34\xa5\xf0\xc6\xfa\x38\xc2\xa7\x52\x48\x3a\x56\xc3\x18\x57\xfb\xad\x57\x0a\x87\x51\xfd\xbd\xaa\x97\xc2\xf0\xb9\x2a\x36\x22\xc5\x66\xe0\xa4\x57\x91\xaa\x29\x94\x8b\xd8\xb3\x67\xa6\x1b\x8c\x4c\xfd\x2e\x20\xee\xa0\x8c\xc6\x34\x07\xe3\x08\x62\xb4\x9d\xaa\x55\xed\x0c\xa1\xc1\xb7\x4c\x79\x16\x19\xb5\x88\x8c\x4e\x91\xf9\x1f\x4e\x1a\x38\x58\xc9\x31\x57\xca\x4d\x71\x58\x46\x46\x74\x7a\x66\x2f\x59\x54\x44\x39\x61\x72\x5a\xd1\xa0\x82\x66\x61\xed\xe6\x1f\x93\x9b\x08\x9c\x0b\xad\xa7\xde\xc3\x87\x0e\xa0\x2e\x7a\x14\x41\xd7\x4e\xfd\x23\xc3\x02\xbc\xa2\xce\xac\x52\xa9\x67\x2b\x3d\xc6\x4a\x46\xb9\xfe\x18\x31\xad\x89\x33\x8a\x02\xbc\x2c\xfa\x2a\x62\x3f\x14\xbc\x8d\xd8\x0f\x09\x3f\xeb\x56\xc5\x8e\x0d\xf9\x56\xf0\xda\x3b\xd2\xe4\x3a\x22\xda\xe5\x2d\x5a\x4a\x85\x7f\x4c\x4e\x88\x46\xbe\xd6\x32\xb6\x63\x64\x7d\xa0\xaf\x22\xd0\x6e\x30\x86\x97\x06\x54\x44\x84\xf5\x57\x9e\x84\x70\x28\x48\x2b\xa2\xf0\x31\xca\x84\xde\x86\xcf\xd5\xc6\x15\xd7\xc1\x05\xaa\x6b\x69\xe2\x86\xdf\xcb\xab\x52\x4e\xdf\xad\xf2\xfd\x95\x46\xfe\x60\x98\x32\xaa\x8b\xd6\x1d\x92\x16\x76\xd3\x38\x3f\x8c\xaa\x3c\x8e\x9a\x7d\x03\xbf\xa3\xfa\x34\x2a\xc8\x6f\xac\xc8\x7a\x1a\xb1\xb7\x91\x31\x96\x3f\xd5\x6f\xa8\x94\x37\xea\x65\xde\x78\x4b\x7e\x46\x18\x77\x76\x42\x04\xdc\xf3\x9f\x9e\x76\xb9\xe1\x69\xc2\xe5\x3f\xc1\x0a\x84\x28\xbd\x2a\x28\xcc\xec\x0e\xcc\xbf\xde\x4b\x62\xfe\x18\x25\x24\xc6\x54\x0e\xb4\x7c\xff\x3c\x2e\xe7\x1c\xae\x85\xff\x22\x24\x31\x2d\x75\xf1\x3a\x84\x43\x4d\x62\x6a\xbb\xc8\xc1\xe5\x96\xa6\x59\xc7\xbc\x35\x0e\x77\xf1\xa8\x28\xab\xa1\x4a\x35\x16\x98\xfa\x31\x11\xe6\x35\xc6\xb0\xae\x96\x83\xfe\x63\x6f\xe1\xa8\xb2\x1a\xd1\xb5\x76\x40\x4e\xad\x4e\x89\x67\xf6\x67\xb4\x4e\xf7\xcf\x4c\xa5\x17\x02\xde\xd9\x24\x7b\x36\xc2\x0d\x1c\xdc\x67\x44\xba\x5f\xad\x60\x7d\x8e\xc2\xf1\x71\x02\x2f\xeb\x36\xd9\x3a\xda\x6c\xbf\x1a\x77\x00\xc4\x76\x0f\x7c\xf5\x08\x46\x96\x3d\x86\x97\x86\xa4\x51\xd7\x72\xa8\x77\x48\x04\x2c\x62\x4b\xd3\x63\xdb\x54\x66\x3b\x68\x11\x94\x37\x8d\x6e\xda\x2a\x71\x79\xab\x3c\x4f\xb7\x0a\x6a\x7e\x1b\xfe\xdd\xc6\x28\x14\x93\x61\xb1\x4d\xde\x37\x4e\x32\xc6\x30\xfe\xc9\x72\x4b\xff\x7c\x59\x86\x52\xb9\x21\x81\x31\xaf\x18\x7f\x63\x6f\x3f\x6c\xf4\x40\xe1\x7e\x5b\xbe\x03\xa1\x8a\x1f\x09\x85\xd7\x75\x53\xda\x0c\x3a\xbd\x28\x83\x31\xd1\x79\x27\xa0\xd3\xd0\x3c\x23\x01\x96\x3b\xd4\xc5\x0f\x63\x92\x37\xce\xc7\x17\x4d\x6e\xc9\xeb\x28\x0d\xff\xc4\x8b\xe7\x0d\x72\xa8\xbb\x97\x7f\x26\xe4\xd8\x7e\x3a\xb2\xc0\x58\x95\x71\x5f\x17\x65\x39\xaf\xfb\xf9\xab\x54\x0d\xe8\xd9\x6b\x1c\x34\xbd\xda\xd7\xb7\x7f\x55\x92\x32\x0a\x53\x94\xb9\x8a\xb2\x2a\xa5\x78\xc0\x18\xbf\x0e\x50\x6c\x86\xd8\xc5\x64\x47\x2e\x3f\x2b\x7f\x0a\x3e\xed\xaf\x90\xd1\xc2\xf5\xed\x85\xd5\x52\x53\xa3\x79\x04\xf8\x3f\x6c\x9e\xde\x35\x54\xf9\xe6\x2d\xc3\x69\xb7\xf3\x9f\x19\xd0\x10\x81\x46\x2c\x74\x7d\x18\xb1\xc8\xf5\xf3\x9b\x9a\xbe\xcb\x61\xc2\xfc\xf2\x37\x08\xc6\x1a\x6f\xfb\xe1\x8f\x28\xfb\x31\xca\x7e\xcc\xa0\x27\xb6\xf6\xe4\x60\x4c\xde\x45\xa0\x36\xb6\x61\x42\xbd\x5b\xf2\x22\x02\x69\xa4\x24\x3e\xe3\x77\x08\xb2\xa9\x5a\x5a\xe5\x03\x72\x2a\xd2\x51\x64\x4e\x81\x84\xc2\xe7\x15\xdb\xe0\x45\x54\xa8\x8d\xdf\x9b\x85\x9c\xae\xe3\x2b\xd6\x05\x63\xc4\xbc\xd9\x92\x9f\x23\x10\x1d\xa3\xf3\x7c\x89\x40\x6c\x20\x81\xda\x5d\xf8\x61\xb9\xfb\x85\xeb\x72\x19\xe8\x1f\xdc\x3a\x78\x6a\xfd\x25\x69\xa5\xf5\x43\x62\xd3\xe3\xb5\xdb\x86\xb3\x58\xf9\x83\x7e\x96\x88\xbd\x87\x6f\xb5\x5a\xc2\x2d\xf9\x1a\x15\x5f\xa0\xf8\xd1\x38\x1d\xf6\x1e\x0f\x7e\xb6\xc0\xda\xe1\xb5\xca\xcf\x61\x25\xf4\x3a\x15\xb0\x20\x98\xcd\xec\x19\x5b\x6f\xf2\x8f\x88\x84\x98\x1e\xe2\x7d\x64\x23\xa5\x7b\x46\x0d\xfc\x16\xd9\x0c\xa7\x9c\xd9\xb8\x93\x80\x11\xbc\x09\x60\xb4\xc2\x87\x9b\xf3\x2e\xdd\xe8\x41\xc8\x30\x2f\xc4\x98\x7c\x4f\x75\xd9\x26\x78\x1c\xe1\xd9\xe4\x54\x11\xfb\xc1\x49\x48\x0d\x01\x3e\xe4\xe0\xb3\xe8\xa1\x80\x19\xcb\x5c\xdb\xb8\x5a\x1f\x0c\xf3\x4c\x33\xd3\x73\x78\xc9\x89\xbb\x63\x5a\xe2\xc1\xd6\x7b\x0d\xbf\x34\x7e\x69\x22\xe7\xc1\xd1\xa0\xf7\x70\xeb\x01\x19\x75\xfc\x0e\x89\x36\x66\xf4\x61\x44\xbd\xae\x61\x8a\xa3\x15\xb1\xe9\x19\x5f\x90\xc5\xdd\x11\xee\xfa\xf3\xf9\x22\x2f\xb8\x2e\x7d\xe5\xa3\x9c\xd8\x32\xdf\x49\x59\x72\xa4\xd0\x68\x2b\xf7\x92\x05\xa0\x58\x04\x9a\xbd\x24\xda\x08\x13\x6e\x44\x7e\xf6\xb5\x73\xb4\xdc\x75\x29\x16\xde\x2a\x35\xa6\xba\xc6\xaf\xc2\xa8\x51\x1d\x51\x4c\x89\xa4\xee\x65\x14\x4a\x82\xd9\xcb\xf5\xa8\x29\xce\x3b\xcb\x7f\x64\xfe\x2a\xa3\x98\x1c\xe6\xb7\x4b\x46\xe4\x96\xc8\x91\x5d\x06\xbb\xb8\x29\xf7\x14\x75\xb3\x84\xb7\xe5\xca\xc0\x68\x6e\x1d\xd6\x90\x55\x36\x9c\x8e\xbb\xb9\xf3\xe0\x85\x20\x63\xa2\x47\xd6\xf0\x7c\x40\x7a\x1b\xa8\x9c\xc7\x7f\x89\x73\x37\x43\xb9\xe7\xdd\x12\x81\x50\x8c\x2a\x10\xe5\x76\x2c\x1f\xb1\x3b\x08\x46\x7f\xa7\xb8\x3d\x2a\xab\x33\x25\x31\x2d\x4a\x62\xda\x1a\xf3\x81\x55\x85\xfe\x5a\x64\xf7\x17\x15\xc3\x5f\x65\xc5\xed\x65\x49\x31\x7c\x09\xfe\x63\x54\x01\xfd\xc7\xa8\x02\x1a\xbd\xe3\xcc\x6c\xac\xae\xd1\xb3\x57\xe9\x82\x35\x20\xe3\x1c\x62\x45\x0f\xf4\x1f\x2f\xc0\x5b\x52\xf5\x7a\x8b\xca\xe0\xf6\x62\x8d\xb7\x78\xb1\x8f\xf7\xf0\x1b\x14\x45\xbd\x9d\x85\x7a\xfe\x78\x11\xd2\x92\xe2\xa9\x16\x6b\xec\x96\x6b\x70\x96\x0d\xc8\x0c\x97\xe3\xd7\x11\xbb\xde\x4b\x41\xb8\xcb\x5f\xd2\x81\xd1\x70\x8d\x9d\xbe\xe6\x80\x7d\xc1\x5d\xde\xf5\x90\x67\xf7\xba\xf0\xc5\x28\x62\x7c\x04\xf1\xc8\x56\x87\x82\xc5\xd7\x9a\x5c\xc7\x66\x0a\xb9\x99\x9f\x04\x9e\x0b\x0a\xcf\x34\xe1\x6e\x70\x95\x9e\x9e\x97\xc6\xda\xa0\xfe\x66\x67\xac\xd1\x88\xbd\x91\x30\x1a\xb1\xa6\xae\x32\xe7\xa8\xec\x38\x0f\x97\x82\x00\x28\x4d\x20\x1a\xd5\xc5\xa9\xe6\x5e\x2f\x4a\xc1\x1f\xa5\x69\x4f\x67\x4d\x7b\x05\xc3\x5a\x21\xb8\xb1\x67\xe7\x93\x11\x9b\x48\xd2\x7b\xd8\xa5\x70\x5d\xcb\x36\xc6\x64\x36\x32\xf2\x67\x1b\xec\xa1\xd3\x36\x6a\x60\xc5\x05\xd1\x87\xa7\x1b\xa7\xff\xfc\x73\x76\x9f\x10\xfa\xa0\x33\x70\xe1\x9f\x7f\xfe\xf9\xe7\x7f\xb6\xe6\xff\xe3\x9f\x7f\x66\x67\x0f\xcf\x1d\x6a\xd8\xed\x64\x04\xba\x71\x7e\xa5\x1b\xc8\x04\xbe\x71\xe2\xfc\xf3\x8f\x43\xed\xd1\x5c\x76\x7d\x23\x81\xe1\x5f\x6e\xd2\x6e\x31\xe9\x5b\x98\x90\x85\xbb\xad\x81\xa5\xb5\x0b\x0f\x85\xc2\xf5\x08\xcc\x5b\x4e\x13\xea\x89\x15\xf6\xcc\x4b\xcf\x71\x00\xa9\x65\x6c\x0c\xd9\x6d\xcf\x41\x67\x5e\x70\x83\x7e\xb5\x8c\x86\x84\xeb\x5f\x98\xe9\x9e\x7a\x97\x1a\x7c\x65\xbf\x4e\x99\x6d\x7a\x7f\x64\x37\x7d\xb6\x86\xf9\xa6\xff\xeb\xed\x50\x6c\x65\xde\x5f\xc2\x2f\xfe\x33\x7a\x19\x89\x37\x4f\x3a\xdf\x4e\xcc\x06\x88\x29\x4d\xc7\x42\x69\xe3\x6e\x33\x28\x2a\x8c\x17\x68\xde\xfa\xfe\x74\x79\x4b\x5b\x1d\x74\x79\x0c\xfe\xd8\x5b\xef\x41\x06\xb2\x9e\x99\xfa\x23\x0f\xb9\x39\x4f\x4d\x27\x8c\x65\xa0\xcb\x19\x13\x4b\x36\x66\xab\x89\xe4\xd3\x88\x22\xe8\x5a\xbd\xef\xaa\x96\xd0\x51\x2b\x68\x8d\x20\xb2\xb1\x46\x17\x8d\xc0\xd2\x2b\xfa\x08\x6a\x3a\x5a\x95\xf6\x12\x53\x21\xf0\x8f\x10\x9a\x3f\x53\xcc\x88\xc2\x5f\x01\x5e\x42\x39\x07\xdf\x3c\x45\x30\x63\x71\xc7\xf9\x1f\x0f\xd3\xf3\x92\x7e\xe3\xc1\x31\xce\x9d\x11\x32\x91\x4d\x77\x5c\xcc\xb3\xbd\x29\x35\xc1\xf8\xd3\xeb\xf2\x19\x5a\x0a\x6b\x92\xc3\xb2\x2b\x22\xd9\x04\x6f\xe6\x9c\x90\x00\xee\x83\x2b\xef\x6a\x64\x93\xbb\x3d\x35\x5a\xf9\xb7\x55\x1b\x95\xff\x48\xe0\x40\x53\xfb\x4d\x38\x0a\xa9\xb6\xb5\x4a\x7b\x5d\xbb\x25\xad\x00\xde\xd8\x6b\x50\x96\x5c\x63\x7b\xbd\xc0\x49\x50\x97\x3d\x30\x84\xaa\xa3\x3f\x74\x8a\xa5\x07\x1a\x5e\x87\x75\x67\xf0\x96\x43\x5b\x8b\xe6\x31\x92\x09\x62\x58\x10\xdd\x38\x24\x9a\xe6\x5f\x0b\x2f\xb1\x0a\x11\x41\xb0\x98\x44\xe9\x98\xc4\xf8\x76\x89\xce\xee\x42\x32\x71\x6d\x0e\x8d\x84\x54\x1c\x5e\x76\x59\xae\x8d\xe4\x9b\x7a\x13\xe0\x1f\xbd\x6b\xd7\xaf\x3a\x4d\xcc\xc4\x0c\xd9\x98\x9c\x44\xa0\x21\xa0\xd0\x62\x63\x32\x31\xbf\xa3\x25\x48\x63\x2f\x8a\x81\x4f\xf0\xa2\x7c\x64\x36\x55\x30\xf0\xbd\x38\x32\xb0\xf1\x21\x8e\xbc\x10\xf8\x2b\xaf\x65\x3a\x1a\xe6\x5e\x36\x2c\x1b\x93\x28\xdd\xf4\x41\x04\x6f\x42\x4c\x09\x1a\xa2\xb1\x4c\xbd\xa2\x8c\x67\x65\xdf\xd2\x32\x28\xca\x46\xb6\x6c\x34\x22\xa2\xac\xa4\x94\xf8\x81\xb2\x3b\x56\xd9\x1d\x3b\xb3\x3b\x56\xc3\xfd\xfb\x3c\xd9\xa3\xdd\xa8\x8b\xca\x53\x53\xbb\xe3\xba\x76\xbd\xee\x02\xdd\xfb\x4f\x17\xe9\xde\x86\x36\x5c\xb1\x7d\xf2\x29\x82\x99\x4d\x22\x0e\x11\x85\x0b\x76\x55\xd0\x5f\x36\xa9\xaf\xbc\x16\xbb\x72\x39\xf8\x4f\x3d\xcb\xa9\xb3\xf1\x86\x76\xbc\x17\x05\x6f\x36\x50\xa7\x6c\x9f\x04\xa3\x1c\x6a\x40\xfb\x17\x6c\xba\x0c\xf5\xa3\x37\x64\x53\xc4\xaa\x00\x18\x2d\x00\xb4\x9b\xee\x9c\xed\x93\x61\x01\x70\x64\x00\x9e\x2f\x01\xf4\xcf\xbd\xf3\x05\x70\xa3\x05\x70\x8f\x17\xf9\xc1\x64\x71\x5e\x9e\x60\x87\x37\x65\xdf\x58\x41\x5a\x98\xef\xfa\x06\x94\xcb\xc7\x74\x30\x26\x17\xa3\xec\xc1\x1b\x93\x56\xfe\x00\xfe\x96\xe5\xcd\xb3\x88\xac\xf7\x68\xf5\x5e\xdd\x5d\x3d\x64\x23\x76\x09\x67\xc7\xc4\x87\x3b\x4a\x5d\x4c\x91\xc3\x5d\x7f\x80\xec\x25\xbb\x3a\xcb\x51\x02\x53\x8a\xd9\xc5\xb7\xbc\xbb\x9c\x7a\x67\x11\xb9\x43\x6b\x2d\x02\x19\xc1\x41\x48\xee\x52\xaf\x56\x42\xe1\xbc\x8e\x5f\x97\xce\xea\x6e\x1a\x55\x9d\x96\xb7\x5b\xf9\xcc\x51\x2d\xe3\x3f\x92\x64\x75\x34\xea\x47\x59\x8d\x46\xbd\xb7\x26\x38\x8c\x47\xec\x48\xc2\x6d\x2d\xd0\xbb\x11\xb1\xe7\xc5\xf6\x8e\xd1\x78\x64\x28\x7c\xdb\x1e\xdc\xe2\x5d\xc1\xf4\x9d\x7f\x98\x9e\x19\xcf\x4e\xc4\xb9\xb8\x75\xc0\x8f\x4c\xcd\xef\xe9\xe7\x38\xf6\x1b\xa5\xd0\x09\x27\xf2\x21\xa2\x73\x50\x8b\x80\x4c\xe0\xd9\x2a\xd3\x75\xf1\xb3\x97\x1d\xb9\x98\xa8\xce\xa6\x3e\x12\xae\x7f\x8d\x49\x7e\x8b\x9a\xc2\x26\x2f\x05\xc5\x14\x68\x7b\x3b\xfe\x70\x19\xcf\x22\x2f\x6a\x3e\x91\xcf\x50\x93\x84\x31\xd9\x1f\xc1\xc1\xc8\x58\x8f\xbb\x62\x3b\xbd\xd1\x78\x34\xaa\x4d\x4e\xb2\x6f\xac\xb7\xde\xf6\x76\x97\x76\x1e\xf5\x9e\x6c\xef\x3e\x06\xcd\x88\xda\xeb\x0e\xd4\x46\x6f\x7b\xb7\xfb\x64\xd7\x53\xf4\x21\xfe\x7a\x34\xef\x82\x60\xe9\xeb\x47\x0f\x34\xc4\x8c\x88\x0d\x22\xb0\x14\x2f\x71\x88\x87\x5b\xbb\x3b\x9b\xf6\x6a\x87\x7d\xfd\x64\x77\xde\xa5\xd4\xbc\x9e\x77\x81\x33\xb1\x41\xb6\x76\x77\x1e\xc4\x1d\x12\xa7\x37\x40\xe2\xf4\x06\x08\xba\x2e\x76\x1e\xf0\xce\x26\x7d\xd8\xdb\xd9\x9a\x77\x21\x64\x41\x87\x04\x7b\xbd\xee\x60\xcb\xdb\x78\x92\x31\xf1\x7b\xfe\xdc\xe3\x1b\x84\xf4\x76\xb6\x1e\x04\xa6\xf2\x8e\xe9\xb9\x07\x7c\xd3\x0b\xc1\x7f\xed\xc5\x9d\xed\x6e\xf7\x81\xee\x90\xcd\xbd\x70\xd0\xf5\x7a\x34\x49\xe0\xb2\x71\x8d\x8f\xcc\xd6\x39\x4c\xad\x60\x97\x3f\x4f\x28\x7c\x5c\xa1\x96\xbc\x0b\x60\x73\xdb\xce\x6e\xde\x0c\x76\xbb\x36\x52\x70\x75\xbb\x9e\xd8\xb2\x2b\x82\x5f\xc7\x5d\x5d\x77\xb7\x5b\x80\xc7\x08\xc0\xe5\xea\xa9\xe6\xb1\x80\xff\xe6\xa2\x4a\xd3\x5d\x50\xc1\x7b\x0b\xb6\xe0\xe6\xe2\x2d\x92\x05\xf5\x79\x7b\x41\x36\xed\x2c\xc8\x9c\xdd\x05\x96\xf9\x68\xe1\x7e\xc7\xe3\x45\x59\xf3\x64\xf1\xd6\x46\xaf\xbb\xa8\x07\xf4\x7a\x86\xde\x7f\xff\xc5\x14\xe5\x44\xde\x13\x5b\x38\x51\xc7\x7f\xb9\xd0\xfe\x6b\xc3\xce\x57\x30\xb5\x4a\x36\x87\x4f\xc6\x9e\x7c\x3a\x82\x2e\xb4\x28\x9c\xd4\x6d\xf9\x6c\xb6\xf7\xe4\xe0\x96\x9c\x8c\x40\xfe\xfb\xdf\x3d\x78\x49\x94\x21\x8f\x5e\x5b\x0e\x5e\x12\x0d\x8a\x7a\x9a\x7a\xc6\x90\x7d\xbe\x42\x8b\x3e\xb1\xbe\x14\xc7\xc1\x68\xbf\x15\x7d\xbd\x24\x63\xf2\x7c\x04\x72\xe3\x85\x30\xaa\x97\xfd\xd2\x91\xdd\xe8\xbf\x56\xc0\x7f\x69\xe0\x3b\x5d\x07\xe2\x2c\xa9\xc0\xfb\x06\xa3\xf4\xd7\x08\x0c\xa9\x1f\x8f\xe0\xd3\xc8\x06\x3e\x6c\x38\x1d\x7c\xbd\xb9\xe2\x02\x6d\xa1\xfb\xf5\x16\xb4\xbe\xcd\x05\x52\xdc\x5a\x20\xc5\xed\x05\x52\xdc\x59\x20\xc5\xdd\x05\x52\x7c\xb4\x40\x8a\x8f\x17\x48\xf1\xc9\x02\x29\xf6\xba\x8b\xb4\xd8\x5b\x4a\xe1\xdd\xdb\x4c\x12\x32\x26\x3f\xb3\x31\x57\x06\x3d\x26\x97\xc5\x5c\x7c\x2a\xbd\xfe\x58\xbc\xf6\x4a\xaf\xdf\xd6\xbf\xfe\x5d\xbc\x76\xd3\xd7\x5b\xff\x5f\xf2\xbe\x44\xb9\x6d\x1c\x0b\xf0\x57\x14\x8e\x76\x06\xac\x3c\x31\x72\xae\x4e\x98\x66\xa9\x7c\xc8\xb1\x13\xc7\x4e\xe2\xdc\x3d\xd9\x14\x40\x52\x12\x2d\x8a\x54\x40\x90\xb2\x9d\x68\x7f\x63\x3f\x68\x7f\x6c\x0b\x0f\xe0\x25\x92\xb2\x33\xdd\x33\x3b\x55\x5b\xdd\x15\x8b\x24\x08\x80\xc0\xbb\xf1\x0e\x29\xb7\x95\xb7\xbf\x18\x6b\xf8\x20\x61\xee\x32\x80\xf9\x04\x5e\x4f\x4c\x78\xd1\x0d\xd8\x9a\xb7\x12\xe1\x44\x9d\xe9\x40\xac\x65\x9a\xcc\xc8\x45\x44\xd0\x5d\xc8\x04\xbe\x36\x4d\xf8\xe3\xab\xc4\x85\xc2\x0b\xf9\xd5\xc4\x39\x8e\xe0\xf9\x16\xd8\x79\x25\x20\x73\x55\x3a\x17\x13\xde\xcb\x09\x3e\x9f\xe0\x41\x9c\xf6\xd8\x3a\x3e\x30\xbe\x9a\x18\x91\xf2\x79\x0b\xe0\x2a\x27\xf7\xd7\x67\xe7\xda\xcb\x5d\xbb\x05\xbc\xd9\x82\x8d\xf5\x94\x29\x1d\x8c\x50\x6a\x85\x9b\x3e\x72\x45\xf2\x66\xb4\xe4\x39\x44\x38\x85\xd4\xa0\x4f\xc0\x13\x03\xe6\xe4\xc5\x04\x2e\x27\x40\x7c\x87\x9b\x78\xd8\x2e\xc5\x85\x32\x96\xe4\x03\x9e\xd6\xac\xd4\xed\x3c\x0e\x05\x6f\xd2\xb1\xba\xe9\x72\x9f\xea\x58\xec\x39\xde\xdf\xd7\xf7\x75\xb6\x6a\x7d\x77\x57\x0b\x22\x9e\xa1\x12\x80\xbd\x9a\xe8\xa4\x60\x13\xf0\x2d\xfa\x01\x6b\xe8\x62\xfe\xe7\x09\x18\x74\xb9\x0c\x03\x17\x43\x51\xee\x61\xca\x04\xc0\x74\x07\x43\xe5\x39\x5e\x5a\xb3\x2e\xc9\xe7\x09\x06\x6c\xbf\x57\x49\x74\x3f\x4d\x1c\xb7\x33\xa2\xbb\x34\x50\xed\xda\x29\xd0\x7d\xdb\x07\x3a\xb6\x05\xd0\x0f\x36\x05\xda\x97\x6b\xbc\xb2\x39\xb0\x2b\xdb\x05\x76\x60\x63\x79\xa7\x2f\xdd\x5b\xf9\x83\x7e\x96\x2f\x3f\x94\xef\x1d\xaa\xcd\x79\x89\xc6\xb1\x07\x6b\x88\x58\x1e\xa9\x9e\x8b\x5d\x2f\x27\x3a\xb8\x45\x0b\x67\x45\x30\x4e\x35\x46\xfc\xcb\x44\x95\x5b\xc8\xdf\xee\x88\xf2\xc1\xd8\xa0\x5a\x58\xfb\x4d\x71\xfd\xfe\xe5\x32\xe0\xbf\x1a\xd3\xbf\xf4\x23\x2f\x88\xa6\x7f\x22\xa0\xbf\x3d\xec\x5d\x27\x26\xc8\x03\x80\x24\x40\x14\xab\x51\xc0\x4c\x79\xa7\x84\xae\xfd\xce\x70\xa8\x96\xd0\xa7\x12\xc2\x4f\x5d\x12\x31\x9c\xcc\xa7\x49\x19\x95\x24\x58\xe7\xe1\x5c\x3b\x1a\x19\xc0\x2b\xee\x8d\xa8\x40\x09\xc8\x2d\xaa\x3e\x70\xa6\x8c\x16\x3e\xeb\x70\x2c\x7c\xaa\xb5\x89\xb4\xb5\x81\x3b\xb7\xd1\xf8\xf9\x49\xfe\xf9\x3c\xba\x6f\x0f\x25\x54\x49\xf9\x7d\xbd\x06\xca\x9c\x1f\xd4\xb5\xef\xec\xc0\x47\x34\x07\x4e\xe4\xbf\xa7\xf2\x1f\x4c\x77\xf7\x1a\xa3\x6e\x5e\xa8\xbc\x3c\x6d\xbd\xf7\xde\x12\xca\xe0\xc7\xa9\x54\x84\xef\x0c\x4d\x38\xcb\x7f\xbc\xce\x7f\x14\xfe\x36\x68\x71\x49\x99\x36\xc1\xac\x21\xe8\xf8\x9c\xdc\x4f\x31\x66\xdb\xb3\xb8\xfd\xd6\x96\xc5\x6d\xc2\x74\x40\x14\xeb\xe8\x3d\x5f\xab\xa4\xe3\xf9\x13\xfd\x3c\x64\x5d\xf4\xfa\xc8\x25\x28\x1c\xdd\x3d\x53\x61\xdd\x26\x64\x4c\x17\xe9\x5d\x19\xf0\x78\xf8\xf0\x89\xff\x08\xe9\x91\x67\x00\x46\x42\xe3\xc5\xcc\x80\x07\x8f\xf5\xef\x85\xa1\xb4\x07\x49\x0d\x0d\x94\xb1\xbe\x9a\xe0\xb5\x2e\x6f\x64\x09\x1e\x2c\x88\xb9\x86\x7e\xfb\xf3\xdf\x87\xda\xca\xe8\xb1\x76\x5d\x30\x57\x66\x28\xba\x13\xab\x7c\xa7\x14\xf3\x9d\x56\x54\x78\x7a\xcf\xff\x39\x1c\x49\xed\xc1\x55\xbf\xcd\xbb\x44\xdc\x35\x7a\x86\x69\xda\x29\xa0\x60\xe8\x83\x8a\x6d\x3b\x23\x86\x01\xea\xd3\x21\x63\xa6\xca\x68\xb0\x60\xce\xeb\x09\xcc\x98\xf6\x85\x5d\xb6\x2e\xee\x37\x7b\xc6\x10\xf4\xd6\x6b\x98\x4a\xb8\xdb\xb5\x97\x8c\x18\x86\x29\x29\xa6\xfe\x75\x55\xdc\x1a\x17\xbf\x3e\xa0\x3d\xa9\x6f\xf7\x25\x15\x55\x37\xd7\xb0\x92\x1d\x7c\xc6\x4c\xf7\x0f\xf3\x96\xec\xb0\x78\x7c\xc5\xda\x93\x57\xcd\xd1\xb7\xfa\x93\x5a\x8b\xc3\x12\xe5\xde\xb5\x9a\xf0\x2e\xc9\x97\x09\x70\x50\xa5\x11\x9b\xe6\x49\xb1\x29\x9a\x49\x90\xdf\xd9\xb4\xce\x2b\x3c\xd8\xa4\x6e\x98\x43\x13\x55\xf1\xf6\x99\x16\x93\x93\x5f\x29\x11\x57\x7f\x27\xea\xe2\xfa\x4b\xb1\x78\xce\xe5\x36\x34\xe9\xbd\x25\x53\x06\x7a\xa5\x45\xbe\xd0\x91\x5e\xe7\x3c\x40\xa1\xcf\x08\x06\x7e\x9b\xf9\xb2\x2f\xe4\xb3\x90\x81\xbc\x8b\x0e\x3f\x72\xf9\x8f\x62\xc2\x55\x3d\x78\x86\xe9\x55\x3f\xeb\x83\xa7\x2b\x86\x0e\xd3\x0c\x0f\x40\xf4\x16\x2d\x18\xd6\x59\xc2\xe8\xb6\x4e\x44\x42\x2c\x1a\x8c\x27\x2a\xa3\xe2\x18\x91\x08\x57\xdc\x30\xe4\xff\x77\xb0\xa2\xf5\xbe\x02\x14\xc3\x90\x73\x97\xff\x8e\xed\x23\xc9\x62\x4a\xb0\x18\x33\x39\x28\xde\x5c\xc3\x61\xe7\x68\x3a\xcc\x30\xda\x8c\x32\x84\xd3\x36\x60\x55\xc7\xb2\xf2\x05\xe3\x7c\x16\xa7\xa1\xd7\x8b\x62\xd1\x63\x7e\xcf\x5f\x2c\xc5\x95\x21\xbf\xff\x90\xc1\xa1\x4f\x8c\x8f\x3c\x8e\xa6\xbd\xe3\xf3\xb3\x27\x8f\x87\x3b\xbd\x49\xcc\x17\x54\x18\x26\x7c\xd2\x39\x1f\x2e\x5a\xd1\xf6\xc8\x97\xf8\x1a\x99\xe6\x96\x11\x8e\x53\x0c\x0d\x3a\x6f\xe3\x26\xcd\x5a\x65\x3a\x0e\xf5\x59\xe9\x7a\x94\x8b\xde\x2a\xc9\xbf\x1c\x48\xe8\x40\xd5\x39\x89\xc0\x57\x69\x56\xa5\x7e\xdd\x04\x40\xa4\x17\x9f\x41\x9f\x9a\x6d\xe2\xca\x39\x83\xb9\x80\x4b\xf9\xb7\x53\xa4\xfd\x32\x29\x25\xd0\x0b\xa6\xd2\xc7\xc2\x71\x2a\x05\xbe\x43\x3c\x0f\x3c\x69\x6e\x94\x1a\xf9\x8c\x9c\x22\x84\x9e\x4a\xf8\xd6\xde\xa9\x54\x25\x30\x66\xe5\xe7\x0a\x9d\xac\x4c\x27\xe5\x2d\x43\x03\x8e\x25\x71\x56\xa7\x65\x52\x87\xf5\xf5\x12\xef\xd3\xe8\x1f\xb8\xba\x3a\x5b\xd8\x92\x26\x42\xad\x31\xba\xf2\x7e\x63\x9d\x1e\xd8\xdb\x97\x1a\x8f\x49\x8a\xb4\x98\xb5\x36\x22\x6f\x13\xe0\x39\x52\xe1\x47\x55\x6d\xe3\xe7\x6d\x62\xf4\x02\x6e\x26\x14\x3e\x4f\x49\x9a\xb7\x99\x54\xfd\x96\x75\x2e\x6f\xf9\x71\x54\x6f\xeb\x8a\x44\x79\xdd\x07\xa0\x7a\x73\xaf\x9b\x9b\x8b\x45\x8b\x3f\xa8\xcd\xdd\x55\x79\xe6\xfa\x2a\xd4\x64\x5f\x25\x01\x59\x61\x94\x09\x1d\xe7\x43\x5d\xa4\x24\x24\xdf\x18\x6c\x8d\x01\x7e\x4b\xf6\x15\xa1\x89\x24\xa2\x62\x52\xa3\xb4\x90\x7f\xb9\xc4\x50\x7f\x5d\x03\x06\x54\x7b\x8e\x99\x04\x0a\x8c\xdb\x94\x4f\x10\x3a\xe4\xce\xa7\xf8\x63\x4e\x4e\x18\xc8\x9f\xe0\xe6\x60\x73\xc6\x74\x0a\xae\x3d\xe6\x4c\x22\x78\xc7\x1c\x16\xc1\xdb\x2e\xa4\xc7\xf2\x4a\x16\xbd\xbe\x4b\xa2\x01\x16\x9a\x75\x6d\x8e\x55\xbe\xb8\x2a\x9c\x0e\x6c\x61\x73\x55\xfd\x9c\x5b\x98\x73\xf1\x80\x39\x71\x04\x47\xcc\x71\x23\xf8\xde\xec\x36\x98\x90\x4b\x72\xc4\x60\x67\xb8\x83\x16\x8f\x9f\x3f\xf1\xf2\xf1\x53\x65\xff\xc8\x91\x07\xeb\x82\xe1\x93\x87\x0f\xb0\x9c\x92\x6e\xf7\xf0\x11\x5e\x8d\xc4\xdd\x1d\x5b\xa0\x56\x75\xc0\x54\xfd\x24\xbd\x8a\x87\x44\xae\xe9\x68\x90\xda\x69\x99\xe0\xdf\x84\xd7\x9d\x54\x4d\x75\xfb\x18\x87\x1f\xcd\xc9\x77\x06\xd8\x27\x7a\xa1\x49\x7a\x6c\xe3\xbd\xdc\x3d\x92\x6d\xad\x74\xe7\xa3\x7b\x8f\xaf\xcc\xa7\x6d\xa5\x10\xef\x0c\x55\xc6\xa5\x54\x65\xd5\xd6\xc0\x5d\xa1\x35\x87\x44\x40\x5e\x0d\x55\xd5\x58\x13\xe6\xef\xc5\x4b\x51\xa5\x1e\x65\x40\x5c\x3c\x74\x66\x40\xb1\x74\x8a\x09\x2f\xb6\xf2\xb1\x7a\x39\xfe\x4a\x50\xc0\xab\x6e\xcc\xcd\xcb\xb1\x50\x74\xd4\x7a\xcd\xc0\x45\xb4\x90\x5f\x17\x54\xd3\xae\xaa\x2f\xdb\x25\x2f\x18\x50\x04\x06\x8b\x5e\x0f\x48\x70\x17\xcb\xa5\x47\x40\x2d\xd7\xcc\x4b\xc0\x59\x0c\x82\xf6\x6a\xa0\x14\x78\xde\xca\xad\xb4\x59\x91\x0f\x72\xf9\x55\xdd\x03\x39\xab\x2a\x1d\xf8\xd1\xb6\xb8\x14\x2d\xf4\x05\x4d\x80\x89\xb3\xe7\x12\x0c\x1a\xc1\xd1\x15\x66\x57\xa9\xc0\x04\x73\xaf\x6f\xf6\x50\xac\x74\x4c\x26\x92\x16\xe2\x5a\x07\x5a\x86\x7b\xce\x9c\x39\xe9\xca\x73\xec\xfc\xa0\x89\x2d\x69\x9c\x09\xf4\xb9\x44\xe7\x97\x92\xb8\x9c\x48\xe9\xe1\x5d\x7e\xff\x93\xbc\x75\x4e\x4d\x70\x03\x9b\x03\x7d\xa4\xee\xaf\x37\x93\x36\x29\xe8\x7c\x52\x94\x54\xad\x88\x37\x58\x40\x8f\xdf\xdd\x79\x56\x05\xe4\x9d\xfb\x43\x2c\x7e\x47\xcd\x11\x2e\x9c\x6f\xb9\x81\x54\xe1\xdf\xa1\x13\xc6\x3b\xa6\xcb\xed\x42\x24\x3f\x4f\xb6\xdf\xd9\x69\x6d\x2f\xd1\xec\x92\xec\x31\x78\xb2\xf9\xc6\xd3\x27\xad\x2f\x24\xf9\x0b\xf7\x2b\x2f\x84\xe4\x55\xd9\xe2\xb9\xfc\xe7\x93\xfc\xe7\x25\x9c\x11\x0e\x43\xac\xe2\xa5\x27\xdf\xd9\x12\xfb\xdc\x19\x16\x0b\x80\x19\x7b\x91\x6f\x49\x49\x9a\xc1\x19\x33\xe1\x3d\x73\x6a\x19\x58\x8e\xa8\xdc\xa0\x7f\xa5\x54\xeb\xb5\x32\x3d\x4a\xb1\xdc\x34\xe1\x33\x6b\x96\xfe\xd3\xff\xd0\x14\x86\x6d\xf1\xff\x95\x2c\x33\x7b\x6d\xb5\xd7\x7b\x0b\xcc\xd2\x84\x95\x3c\x65\x4f\xef\x19\x1c\xa6\xa6\xa9\x6b\xc3\xf3\xbc\xa2\xe6\x61\xaa\xeb\xeb\xbd\x61\x45\x85\xb5\xcf\xcc\x84\x43\x46\x4a\x89\xc9\x4b\x39\x5a\x61\x0a\x91\xc9\x34\xe1\x23\xd3\x31\x74\x9f\x3a\x09\x1e\x9e\xd9\x7d\xb3\x89\x70\x22\xcd\x48\xa4\x70\xa3\x73\x32\x08\x8b\xae\xed\x8f\xcc\x5c\x97\xd6\xb7\x2f\xbf\x20\x5e\xcf\xc9\x27\x06\x17\xb8\x53\x4a\xc6\xe6\xeb\x35\xbc\x6c\xef\x80\x7e\x50\xac\x73\x5f\x89\x47\x2b\x64\x9d\x74\x8c\x61\x9a\x57\x8a\x81\xf6\x9f\x95\x56\xa1\x4a\xd7\xbb\x28\x86\xe7\x37\x84\x94\xc5\xf1\xe2\x0d\x03\x8a\x02\x38\x5e\x9d\xe4\xdc\x30\x45\x51\x97\xab\xd8\x87\xe7\x02\xbe\x30\x70\x51\xcc\xc6\x66\xa7\x0c\x4b\xbb\x43\x94\x54\xc3\xf9\x0e\x94\xae\xb1\xcf\x7d\x2a\x62\x6e\xc0\x7c\x62\x02\x4f\x6e\x58\xd2\x5c\x39\x43\xff\x88\xa4\x9e\x3c\xc2\xaf\xc5\x98\x08\xb7\x4b\xf0\x43\x8f\x5f\x73\x24\x61\x01\x03\xcc\x55\x88\xe4\xc6\xc8\x62\x5b\xf8\x5d\x1e\x83\x73\x84\xf1\x39\xa0\xd5\x0d\xb9\xa3\x15\x77\x04\xdf\x39\x65\x04\xe5\x18\x13\x52\xf9\x5b\x58\x74\x8c\xab\xc5\x9b\x91\xd8\x28\xa8\xee\x32\x55\xf1\xab\x1e\x87\x2d\xac\x2b\x09\x09\x6a\x4f\xfb\xa8\x5c\xd5\x92\x04\xa9\xe7\x28\x1b\x94\x6e\x13\x38\x43\xb9\x67\x3c\x91\xdc\xc6\xba\xd2\xbb\xc1\x13\xa0\x20\x2c\xb6\x2a\x26\x9b\xbb\x11\x49\x7c\xf5\xd5\x34\xd9\x4a\x6d\x2a\x7e\xc0\xff\xab\xe9\x22\x8c\xe9\xe9\xd2\x71\x31\xdd\x87\x36\xd5\x76\x82\xca\x54\xb5\x94\xfb\x06\xa7\x1b\x38\x24\x53\x13\x0c\x25\x37\xf5\x4d\x13\x47\xc5\xb5\xb7\x17\x8c\x64\x95\x09\x55\xc7\xa5\xf5\x71\x83\xfa\xb8\x8f\xec\xcd\x57\x14\x36\x94\xef\x28\x7c\x28\x56\x0f\xdf\xae\xa2\x40\x6d\xd5\x1f\xd7\x41\x69\x5f\x8d\x89\xc9\x98\x2d\xba\x5f\x34\xfb\xad\xd9\x4c\x63\x64\xb5\xd5\x93\x7a\xab\xdd\x5a\x67\xbb\x45\xb3\xa7\xcd\x66\x45\x67\x65\xab\x9d\x26\x90\xa3\xd7\x5b\xe2\xe8\x0e\xfb\xa6\x72\xca\x4f\x24\x77\xcc\xc3\xd3\xf2\xc3\x95\x3c\xb7\x32\x83\x89\x73\x49\x44\xa2\x5f\x6b\xb5\xc9\x45\xe8\xb0\x84\x73\x8d\x15\x39\x5b\x9b\x6b\xd5\xe5\xb3\x8d\x39\x4c\xd6\x65\xc2\xb7\xdb\x77\x5c\x21\x94\xb7\xe8\xf9\x7e\x91\xd5\x98\x3d\xbb\xd5\x18\xec\x50\x4d\x1e\xab\xe0\x1e\xde\x66\x88\x07\xb7\x9b\x7c\x6e\xf9\xdc\xd6\x61\xd5\x63\x24\x81\xf0\xf6\xb3\xa6\x9f\xed\x70\x5b\xcf\x28\xd5\x65\x6b\x13\xd2\xc4\x21\xd7\x81\x73\xe4\xc2\x75\x54\x63\xb3\x11\x39\x89\xc8\x75\x40\x0e\xa8\xf0\xad\x28\x5e\x11\xe5\xdc\x68\x02\x4d\xb6\x39\x93\x56\x7d\xee\x94\xf7\xe5\xb5\x54\xb3\xe8\xa9\x0e\x7c\x2d\x28\x48\xee\xf3\x72\x6a\xbf\xd4\x0d\x80\x09\xfb\x2a\x20\xc6\x7e\x61\x82\x48\x52\xb6\x08\x84\xce\xa9\xcd\x17\xd0\x3b\x57\x56\xea\x5e\x90\xe0\xf3\x2b\x5f\xf4\x30\x6f\x9a\x65\xe4\x7e\x97\x8d\xa8\xda\xdc\x29\x48\xd8\x69\x5c\x09\xa6\xcc\x3d\x83\x18\x83\x39\xca\xa4\x1f\x27\xca\xae\x08\x51\x22\xd5\xd8\x7d\xed\x47\xe3\x33\x18\x07\xea\x46\xc5\x91\x4b\x79\x07\xb9\x0e\xba\xeb\xc4\x2a\x8d\x8c\x14\x7d\x73\xcf\x2c\x71\xd7\xf8\xdb\xbd\xfc\x64\xea\x9e\x71\x37\x96\x7a\xf1\x5e\xdc\x9c\x93\x9c\x92\x5b\x50\x0b\xa5\xc5\x44\x55\x73\x28\x57\xd3\xc0\xb9\x5e\x92\x18\x01\x1d\x02\xc9\x8f\x02\xe4\xdf\x72\xf2\x69\xd2\xe2\x28\xf6\x83\x5e\xa0\x55\x6a\x69\xfb\x31\xd0\x53\x7b\x97\x5c\xb2\xc2\x03\x27\xb2\x5c\x88\x2c\xcf\x04\x77\x6e\xe3\x84\x99\xb0\xfd\x78\x5d\xf5\x35\x47\x1c\xaf\xce\xe3\x92\x08\xc9\x0a\xf0\x6b\xd5\x7c\x12\x5c\xbb\x86\x4f\xd5\x03\x0c\x3a\xa4\x56\x7f\x54\xee\x31\x61\x0e\x52\x74\xcc\x25\xce\xa4\xc8\x12\xca\x3f\xfb\x90\x39\x4c\x8a\x2c\x9e\xbc\x1a\x43\x5f\xfe\xe9\xe7\x56\x42\x96\x4b\x28\x4b\x46\xc2\xa6\xa1\x70\x4e\x76\x19\x64\xe0\x99\x35\x6b\xa1\x67\xa2\x94\x72\x2a\x48\x62\x16\x92\xca\x9c\x41\xbf\x62\x10\xcc\xb4\x41\x10\x97\xf6\x44\xc8\x1d\x9e\x53\x32\x91\xb2\xaa\x69\xcb\x6f\xdd\xf0\x39\x9c\xd4\x80\x78\xd2\x04\xe2\xa5\x02\x5c\x1a\x21\x58\x7a\x41\xb2\x0c\xe9\x55\x8f\x4e\x26\x2a\x43\xd0\x2e\xfa\xa5\x6e\x05\x5f\xa8\x20\x82\x06\x65\xea\x4c\x9a\x2e\x62\x4b\x05\xc6\x15\xd7\xbb\x1c\x80\xd1\x45\xd1\x65\x12\x56\xfb\xa5\x0b\xe0\x83\x4d\x4f\xb7\x65\xd3\x03\x70\xa3\xc5\x45\xa5\x45\xc3\x7f\x53\x3e\xe6\x16\xbd\x28\x01\x6b\x4e\x7c\xc5\x86\x14\x12\x37\x21\x0a\x69\x8d\x2e\x17\x08\x1e\xf4\x25\xc8\x27\xfa\x0c\x31\x48\x2a\x47\xcc\xea\xd0\x4f\x9f\x2f\xc7\x9d\x42\xa2\x3a\x5d\x3e\x18\x9f\x8c\xdf\x8d\xeb\x59\xd4\x26\xc9\xaf\x1f\x77\x59\xf4\x43\xc7\x89\x57\x9c\x80\x0f\x41\xa2\x4e\xbc\xd8\xaf\x76\x9d\x18\x77\x79\x5c\x4f\xdb\xd2\x38\x4e\x3b\x75\x09\x9e\xa8\xc9\x01\x92\xe6\xf7\x36\xaa\x30\x95\x29\xac\x82\xdc\x7a\xbc\xe1\x8d\xeb\xc7\x1b\xfc\x3d\x8d\x37\xf7\xf0\x2a\x50\xe6\xe6\xb5\x09\x61\xb2\x3d\xbf\x47\xd6\xf1\x3c\x4f\x3a\xe7\x75\xee\xd1\x21\xc1\x54\x5a\xec\x52\xc9\xdd\xfd\xb6\x8e\x7a\x2f\x02\xe2\x25\xca\x36\xbd\x68\xf6\x94\xa7\x07\xe8\x27\xe8\x8f\x90\x6b\x30\xec\xb3\x8d\x91\x5b\x40\x67\xb6\x00\xb6\xa7\x0e\xa5\x67\x89\x33\x26\x7f\xec\xc0\x7d\x18\x7e\x35\x61\x99\x74\x58\x97\x1a\x4c\xea\xfe\x26\xf0\xcf\xec\x39\x49\x92\xf6\x10\x96\xe7\x02\x16\x72\xbe\x30\x4b\xcc\x35\xe8\x74\x5d\xed\xc1\x37\xca\x5b\x56\x7b\x27\x73\x8b\x1e\x9b\xc0\xbe\x23\x3d\x9e\x29\x04\xbe\x24\x2c\x81\x14\x04\x64\x89\x59\x73\x41\xa7\x75\xfa\xaf\x18\xc5\x77\x49\xcf\x88\xab\x18\x0d\xfd\x60\x36\xa3\x1c\xf0\xd9\xb3\x8e\x97\x2b\xe3\x2a\xfe\x77\x49\x26\x72\x74\x17\x0e\x7d\xe2\x26\x92\x62\x56\x98\x97\x5f\x65\x5e\x86\xe4\x5b\x25\xe3\x7b\xa8\x79\x14\xba\x0b\xd7\x1b\x6a\xa7\x5c\xf5\xb1\x2a\x1e\xaf\xb1\x20\x41\xe9\x97\x1b\x26\x10\xb7\x05\x22\x34\xfc\x94\xd1\x79\xb5\x03\x10\xf3\x03\xda\x55\xc7\xf3\x3c\xd1\xcd\x55\x1b\xf6\x76\x6b\x7e\x05\xbb\x53\x9f\xb4\x4a\x6e\x4f\x4d\x1b\x00\x75\xb1\xd9\xe2\x51\x51\xbd\xbe\x21\xa3\x7c\x57\x11\x30\x95\xad\xed\x64\xa9\x92\x0f\x00\x4b\xec\x79\x40\x7c\xc5\x58\xcd\x7c\x65\xa7\x89\xe2\x06\x42\x72\x03\x5f\x73\x03\xbb\x7c\xd1\xc7\x17\xf1\xad\xa6\x27\x78\xda\x31\xaf\x1d\x84\x59\x5c\x92\x54\x2d\x48\xbe\x73\xdb\xde\x28\x81\xaa\x2e\x0f\xa5\xca\x27\x79\x9e\x68\x1f\x90\x98\x07\xd3\x20\xa2\xe1\xb6\x3a\x02\xbf\xe5\x0e\x15\xed\xf2\x67\xde\xec\xca\x8e\x80\xee\x49\xd2\x30\xb6\x7d\x60\x47\x8a\x3e\xec\xb6\x01\x40\xfe\xca\x43\xf9\xca\x13\xf9\xca\x95\x6a\x3d\x4e\x6e\x2c\x22\xc1\x7d\xea\x5d\xb5\xb9\x9a\x24\xbe\x10\xe1\x86\x47\x49\xee\x6c\xe2\x05\x09\x65\xe1\x9f\x2a\x1f\xb1\xdf\x45\x72\x7f\xd0\xc8\xe6\xa0\xab\x2d\xc0\x61\xbe\xb2\xd4\xf3\xb8\x9f\x24\x1d\xbe\x38\xfb\x92\xbb\xc1\x69\xe2\xa8\x0c\xb8\x4b\x1f\x7d\x49\xfc\x80\x9c\xba\xe4\x50\xd2\x85\x22\xfd\x6d\xee\x91\x33\x4e\x74\xb6\x5c\xd5\x4d\x99\x25\xf7\xca\x25\xbb\x09\x8a\x62\x17\xc9\x8d\x39\x84\x84\x2d\x80\xa6\x76\x0a\x34\xb3\x7d\xa0\x6f\x6d\x0a\x2c\xb4\x39\xb0\xe7\x6a\xfa\xe7\x49\xe1\x1c\x24\x02\x39\xce\x97\xd2\x77\x26\x9a\x04\x53\x03\xe6\x49\xee\x6a\xe4\xf3\x24\x88\xa3\xe3\x68\x12\xe7\xfe\x42\xd3\xf8\x83\xba\x59\xf9\x6a\x96\x06\xa1\x77\x80\x7e\x44\xf5\x7b\xef\x13\x9f\x57\xef\x71\x1a\xb9\xb3\x5a\x1e\xe1\x2c\xd8\xe8\x2b\xab\xf4\x7e\xe5\x92\x8b\x24\x77\xb7\xd1\x53\x0c\xd3\x04\x33\x8f\x9d\x26\xf2\xf1\xa5\x7a\x0c\xc7\xdd\x2c\xae\x2e\x3f\xe4\x62\x90\xaa\xfb\x88\x69\xde\xce\x93\xba\x10\xc1\xa5\x10\xa1\x4e\x1d\x4e\x3a\x48\x5f\x9e\xc3\xeb\xdb\x26\xe4\x57\x53\x45\x8e\x74\x40\x49\x02\x85\x50\x7f\x92\xc0\x98\x56\x08\x06\xbb\xb2\x7f\xb0\x6b\x24\x62\x9a\x1e\x9b\x70\xdd\xca\xce\x51\x9a\x9e\xc5\x35\x45\x52\x95\x58\x8d\x84\x15\xc6\xca\xd3\xcd\x89\xca\x7a\xaa\x01\x2f\x6e\x5b\xdc\x0f\x63\xea\x91\x3b\x3b\x92\x30\x98\x6b\x38\xeb\x5a\x2d\x6e\xb1\xd7\x2a\x01\xc0\xab\x66\x9c\xd7\x23\x4d\xc3\x56\x64\x39\x81\x7d\xac\xae\x79\xa2\x2c\xa0\x18\xa2\x83\x81\xe3\x0d\xfe\x78\x62\xa7\x16\x05\xf6\xd4\x76\xc1\xbd\xb6\x13\x41\xb0\x78\x0d\xad\x9b\x3b\x5c\x08\x64\xaf\x09\xb8\x89\x24\x68\x07\xba\x57\x49\x7a\x90\xd9\x49\xde\xdb\x64\x79\x79\xa7\x9e\xec\x14\xdc\x03\xbb\x90\xdd\x2f\x29\x14\xd2\xdb\xce\x66\x78\x9a\x7b\x6d\x2f\x44\x5d\x3f\x19\x53\xa2\xf9\x99\xbf\xae\x06\x06\x29\xf5\x44\x4e\x85\x39\x97\xe4\x2a\x01\x2d\xbe\x4d\xd6\x72\x9a\x63\x39\x3d\x54\xb8\x9e\xd1\x6a\x4e\x89\x72\x9c\xbe\x20\x13\x13\xdc\xb1\x9d\xe4\x33\xdb\xad\xcc\xec\x69\x19\x15\xd7\x7c\x35\x13\x24\x2c\xb4\x28\x84\x9d\x15\x26\x1d\xf9\xa6\xb4\xd2\x71\x40\xc2\x8a\x72\x88\x06\x87\xf6\x8e\x42\x41\xb2\xa6\x3a\x36\x9d\x48\x3d\xad\x2d\x76\x2a\x7f\xef\x79\x5a\x63\x96\xf7\xdb\xa3\xa4\xa2\x52\x4c\xde\x79\x50\x6d\x72\x9d\x90\xea\xb3\x47\xed\xaf\x8b\x4a\x60\x61\xd1\xf6\xb1\x0e\x45\x93\xeb\xde\x77\xd0\x43\xc3\x93\xaa\x67\xee\x00\xb5\x19\x8e\xc6\x9e\xda\x6f\xe5\xd2\x3c\xc5\xa4\x4f\xfd\x75\x5d\x80\x7b\x58\x1d\xb9\xa9\x97\x5d\x92\x6f\x5a\xc1\x02\xbf\x26\x2a\x2e\x14\x9c\x2b\xa9\x8b\x9d\x00\x0e\x80\x39\x5d\x68\x4b\xf4\x16\x3b\xb1\x17\xc8\xf1\x69\xcd\x26\x3c\x53\x60\xad\x3a\x71\x0f\x54\x27\x12\xac\x9f\x51\x67\xd6\x84\x98\x03\x3b\x76\x66\xa5\x14\x57\x03\x63\x1d\xf4\x85\x60\xa8\xfb\x1b\xab\x8e\x9a\x51\x5f\x12\xe2\xaa\x51\x5f\x55\xa8\xbb\x5f\x04\x7b\xd1\xa2\xa3\xfd\x7c\x4e\xcd\x78\x2f\x77\x5f\xc7\x7b\x15\x28\xfb\xdb\xa6\x38\xf9\x76\x53\x08\xdb\xd9\x8c\x00\x73\x59\xa3\xc9\xd3\xcd\x5e\xbe\x6d\x53\x8c\x55\x93\x07\x75\xb9\x75\x2f\x71\xde\xc0\xbb\x36\x6a\x49\xe6\x64\x2f\x41\xaa\x8f\x99\xc5\xde\xf8\xb0\x03\x91\x69\x47\xe6\x5d\xe3\x1e\x5d\x06\xf7\xb2\xfb\xc6\x1a\xde\xb6\xd2\x76\xca\xed\x3b\x3b\x52\xcf\x8e\x80\x7e\x43\x47\xa4\xbe\xdd\x5f\xaf\xe1\xa0\x5b\x34\xa8\x47\x43\xfa\xb1\xd6\xde\xd9\x03\x29\x32\x1c\xdb\x6f\x51\xab\xa1\xe7\xb6\x94\x25\x41\x0f\xa0\x62\xb8\xd9\x13\xbb\x0f\xf4\x44\x8f\xe8\x83\xbb\xc0\xae\x86\xf2\xee\x0e\xfa\x69\xce\x95\xa8\x87\xf3\x61\x53\x3c\x0e\xcb\x03\xc0\xdd\xb9\xe4\xf3\xb2\x2d\x9b\xc9\x7f\x54\xc4\x72\x11\xed\x2d\x5f\xc3\x50\xc2\x3c\x1b\xca\xda\x84\xa3\xc4\x91\xec\xc6\x8f\xd7\xf0\xbd\x53\xbb\xe4\x56\x7f\x14\xe1\xe1\x82\x09\xaf\x3b\x15\xf3\xdc\x25\xda\x99\x51\xc2\x55\xb2\xda\xef\x89\x3a\x25\x9f\xe9\xa2\x63\xc6\x92\xc7\x5e\x8a\xaf\x1a\xf0\x72\x82\x21\xaf\x30\x71\xe2\x11\xb7\xe8\xc4\x96\xbb\xc3\xda\xde\x9a\x6e\xe4\xa8\xcc\xdf\x4c\x5a\x02\x87\x83\x8a\x7a\x51\xc7\xeb\xa0\x91\x22\xba\x47\xd9\x7a\x4d\x4c\x08\xd5\xa0\x98\xc5\xb8\x18\xd4\xdb\x38\x49\x93\x72\x17\x7a\x3e\x3a\xef\x12\x92\xcf\x58\x27\xb5\x93\x6c\x35\x9c\xc5\x89\xb0\x9f\x0e\x9f\x3e\xb8\x67\x54\xa4\x87\xb3\x04\xae\x70\x3d\x08\x75\x7e\xa8\xbd\x77\x1d\x81\xfb\xe7\x96\x3a\xaa\x04\x8e\x3d\x7b\x67\x0d\xa9\x53\x33\x24\xe2\x8e\xa2\x74\x8f\x3a\x44\xbc\x06\xdf\xd9\xb4\x34\x4e\x99\x6e\xa6\x2c\x40\x92\xf0\xcc\xc9\x41\x02\x02\x98\x09\xec\x95\x9d\x01\x7b\x2d\x37\x6f\x02\xec\x2d\x6a\x31\xdf\xec\x50\x82\x22\x93\x3c\x38\x01\x17\xe3\x74\xb1\x07\x37\xb4\x27\x92\x7d\x06\xe0\xee\x4b\xd8\x3b\xb0\xa9\x64\x55\xa9\x14\xd4\x8f\x92\x35\xca\x3f\x1f\x92\xc2\x2b\x4f\xa2\x01\xbc\x48\x1c\xc6\x89\xe1\x05\x99\x61\xc2\x2b\x75\x91\x2c\x69\x64\x98\xf0\x3c\x71\x26\x1c\xde\x4b\xe1\xfe\x45\x02\x78\xa2\x37\x27\xaf\xf4\xaf\xe7\x09\x31\x4e\x62\xea\x05\xd1\xd4\xb2\x2c\xc3\xfc\xaa\x5c\xf5\x3f\xb7\x8a\x3a\xef\x48\x64\x89\xf8\xfd\x72\xe9\xf3\x7d\x9a\xf8\xe8\x3d\xf9\x26\x69\x39\x9d\xa5\x58\xec\xa3\xe9\xc4\x12\xd5\xea\xec\x89\x6a\xb6\xa7\xcc\x87\xcf\x09\xba\x6c\x61\x7a\xfb\x8f\x9d\x58\x30\x27\x4b\x0e\x11\xcc\xf3\x88\xb3\x4f\x89\xf3\x31\x21\x86\x1b\xd2\x24\x39\x95\xd2\xb9\x09\x5f\x3a\x04\xb5\x17\x89\xfc\xe4\x4f\x09\x51\x09\xd6\x7a\xf8\xef\x60\x45\x79\x24\x35\x17\xf3\xab\xa9\x57\xe4\x0d\x9a\x67\x30\x88\xf2\xe5\xaf\xd8\xa7\x94\x71\x2a\x67\x0b\x75\xe5\xfa\x7d\xb2\x09\xf5\x5f\x92\xc2\x22\x15\x85\xb8\x61\x2c\x15\x22\x96\x5b\xc6\xd5\x75\x18\x18\x26\x88\xd0\x99\x71\xf0\x43\x67\xc1\x21\x0d\xbb\x57\xc5\x0f\x55\x05\x39\xac\x53\x8e\xac\x96\x86\xed\xcb\x90\x86\x52\x5a\x0f\xdc\xb9\x21\x05\x75\x34\x44\xb9\xe1\x76\xdf\x1f\x1e\xe6\x2b\x17\xd1\x6c\x10\x08\x7f\x91\x2f\x97\xce\x96\x83\x10\x55\x69\x12\x06\xd1\xbc\xa7\xe3\x0f\x64\x4b\xdf\xb4\xe7\x24\x0a\x15\xf0\x89\x10\x0c\x46\xdd\xb9\x24\x28\x91\x67\x80\x21\x38\x8d\x92\x25\xe5\x7e\x24\x0c\xc9\x19\x65\x83\x49\x1c\x09\x03\xeb\x01\xfa\x3c\x28\x6f\xbb\x29\x4f\x24\x1d\x30\x96\x71\x10\x61\x5e\x6e\xfd\x20\x4e\xa5\x02\xea\x1b\x60\x44\x71\x24\xa1\xa0\x3a\x15\x43\xae\x86\x8a\x11\xc2\xc9\x28\x37\x89\xa0\x6d\x81\xf2\x5a\xef\xe8\x01\xdf\xd1\xe0\xb7\x3c\xd3\x6f\xc7\xf3\xc7\x79\xa6\xdf\xae\xfd\xda\x0c\xc4\x4b\x5a\xb7\xea\x65\x40\x82\x98\xcc\x09\x0b\xb1\x2c\xb5\x8a\x23\x80\x4f\x45\xfc\xc0\x1a\x3d\xf2\x42\x05\x2c\xd4\x30\x21\x53\x3f\x25\xd8\x78\x21\xa2\x85\x08\x44\x28\x17\xa3\x1f\xb6\x3b\x51\x40\x2d\xcc\xb6\x8a\x22\x4c\x44\x03\xa4\xf8\xbd\x05\x1f\xdc\xef\x2d\xd8\xe0\x7e\xbe\xe7\xd5\xcd\x66\x22\xea\xc9\xa6\xc9\xa2\xc7\x62\xee\xf9\x7c\xc0\x83\xe9\x4c\x0c\x86\x3d\xe1\x5f\x8a\xc1\x22\x15\xbe\x57\xec\x51\x9a\xf8\x7c\x90\xf8\xa1\xef\xaa\xad\x0d\x44\x40\xc3\xe2\xe9\x60\x11\x5f\x0f\x6e\x68\xb2\xf2\xd9\x3c\x10\x37\xb4\xd2\x13\x71\xe3\x10\x21\xe5\x6f\xae\xeb\x56\xb0\x9b\xdf\xfd\x87\x63\xfc\xe3\xae\xc0\x1c\xf8\x2a\x2e\x29\x0a\xdb\x3e\x67\x3a\x98\x50\xcf\xf7\xf0\x5a\x43\xd7\x20\xf1\xdd\x38\xf2\x28\xbf\x52\x10\x95\x84\x44\x65\xf6\x33\xe5\x8a\x13\xe3\x10\x13\x91\xf6\xd8\x55\x4f\xcc\x82\xa4\x87\xd5\x6e\x2a\x43\x1b\x77\x73\x0a\xbb\x86\x45\xdb\x96\x57\xed\x45\x91\xbf\x1a\xa9\xc4\xa6\x8e\x71\xf7\x75\x40\xb2\x58\xe1\xea\xac\x03\xad\x3f\x26\x60\xcc\xb8\x3f\x31\xe0\xde\xff\xbc\xa0\x19\x4d\x5c\x1e\x2c\x85\x7d\x2f\x50\xa5\x21\x09\x77\x22\xd3\xe2\xfe\x32\xa4\xae\x4f\xee\xfd\x33\xb9\x37\x05\xc3\x30\xcd\x91\x61\xd8\xdc\xcc\xab\x37\x2e\xdb\xe0\xe4\x5c\x90\x08\xed\xda\xe9\x66\xf1\xd4\x39\x09\x1b\x4b\x97\x2f\x55\x10\x4d\xe2\x1c\x26\x86\x86\x09\xb3\x90\x10\xf4\xd8\xf9\x02\x8b\xb0\xe9\x59\x55\x88\xfd\xae\x8f\xd2\xef\x30\x4f\x9d\x2e\x08\x66\xc9\x2f\x60\x2f\x2b\x46\x9c\xd0\xde\x84\x0e\x98\x1f\x86\x83\x24\xa4\xc9\x6c\x10\x23\xac\xe2\x82\xf7\x25\xe3\x23\x86\x3e\x7b\xc2\x65\x2f\xb2\xcf\xf1\xaa\xfb\x56\xf7\x07\x78\x34\x9a\xca\xcd\xac\x7d\x42\xdd\xa2\xe7\xdf\x62\x56\x5d\x73\xf2\x0c\x05\x08\xd3\x50\xf9\x68\x75\x52\xf6\x55\x9c\x87\x26\x76\x36\xb9\xce\x9b\x90\x31\xf9\xa3\xcc\xf1\x5b\x66\xf2\xc5\x32\x5f\xab\x26\x39\xaa\xa5\xd0\xbc\x13\x55\x82\xfa\x9f\x6d\xc4\xad\xc8\x9d\x9f\x86\x72\x2f\x8a\x2c\x9b\x05\x83\xa7\x92\x17\x2a\x1b\x04\xc7\xd3\x4e\x15\xdd\xa2\xca\xa9\x63\xb6\xa1\xe3\x94\xa0\x0b\xdc\x5c\xc0\x79\x4a\x52\x8c\x6c\x51\xaa\x4f\x99\x87\xf3\x96\x2f\xe3\xab\xbc\xfe\x6a\xa3\x31\x57\x39\xef\x7a\xed\x53\x6d\x8c\x70\x9e\x12\xa2\x87\x57\x25\x51\x84\xd2\xab\x6e\x31\x39\x35\xa3\xbb\x95\x31\xeb\x0f\xd5\x83\xb5\x09\x57\xad\x78\x3b\x26\x79\x84\x91\x95\x2c\xc3\x40\x48\xcc\xbc\x7b\x6f\x8a\x81\x29\x9a\x84\x53\x3e\xf5\x25\x03\xbc\xec\x40\xfc\x0d\x44\xaa\xbb\x2c\x3d\x57\xea\x7e\x5b\xce\x5b\x05\xf9\xb3\x50\x8a\xc5\xf3\x90\x18\xdf\x58\x48\x25\xab\x2c\x29\xa5\x02\x50\x4c\x08\xb5\x0a\xe1\x2a\xc4\x6a\x1e\xc8\x74\x76\x15\xa7\x11\x92\xb6\x8f\xf5\xef\x99\x61\xc2\xbe\xfe\x2d\xf9\xf2\xe1\x2d\x79\xce\x7e\x98\x4b\xa5\xe3\x02\x89\x90\x79\x44\xf1\x8a\xd3\x65\x8d\x74\x1b\xb6\xa1\x69\xf6\x6e\xd1\x76\x35\xd8\x19\x0e\xb1\xd5\x25\xc2\x27\x4e\xfa\xb4\x53\x54\x92\x12\xcb\xa9\x90\xb2\xd7\x0b\x53\x0a\x2e\x8a\xf8\xd3\x10\xcb\xb6\xdd\x48\xc8\xaa\x42\x4d\x2b\xe2\x2f\x82\x28\x4d\x1a\x38\x8f\x86\x5a\x39\x33\xbb\x8d\xdb\x74\x91\x4c\x1a\x92\x62\xa6\x5d\xe3\x2d\xc3\x6d\xc3\xad\x4d\xb8\xe8\x00\x9b\x5f\xa2\xdc\x51\xe7\xf8\xf8\x86\x3b\xa3\x5c\x34\x09\x5d\x9c\x72\x4d\x7b\xd7\x70\xde\x3a\x8d\xe8\xf7\x9d\xe1\xc8\x18\xea\x12\xad\x36\xfe\xbb\x86\xe3\xd6\xb6\xe7\x92\x6b\xa8\x90\x74\xc9\xcb\x54\xf4\x39\xde\x54\x01\xe9\xbc\x7a\xeb\xba\xbc\x05\xaa\x02\xec\x66\xc4\xff\x79\x48\xfe\xff\x8a\xf6\xc7\x75\xa9\x44\xfa\xf7\xc8\xfb\x77\xfb\xa6\x91\xb3\xfe\x93\x0e\x38\x79\x55\xd1\x9a\x82\x69\x24\xc5\xae\xc9\xc0\xf5\xa5\xf0\x5d\xee\xb8\xc2\xcf\xe3\x50\x0a\x0a\x2b\x8d\x82\xdf\x9a\x28\x58\x61\x36\x83\xfb\x5d\xba\xa1\xf7\x2c\x72\xe6\xe4\x5b\xa8\x82\x28\x2c\xdf\xcc\xd3\xae\x5f\x77\xcc\xf0\x5b\x28\xa5\x05\x73\x0d\x67\xb5\x11\x53\x28\xa8\xce\x2d\x93\xea\xa6\x24\x32\x47\x67\x44\xd7\x68\xc2\x9a\xec\xf6\x19\x11\xa0\x6f\xf8\xd5\xc4\xdb\x18\x3e\xc3\xe1\x8c\xf4\x25\xb8\xab\xbc\xee\xa1\x13\x72\x78\xa7\x49\x20\x65\x28\x79\xbf\x0d\xb7\x59\x6a\x9c\x23\x42\x7c\x67\x4e\xce\x42\x65\x4b\xde\xa3\x10\xf9\xa4\x92\x00\xdc\xac\xa6\x98\xec\xe4\xff\x67\x05\xff\x8f\x4c\xcc\x33\x29\xa5\x26\x8b\x7e\x91\x72\x93\xfc\x48\x8b\x55\x6c\x21\xbc\xa2\x86\x2d\xe3\x24\x50\x76\x20\x3c\x81\x09\x5c\xad\x38\xa9\xad\x96\x8a\x5e\x32\xc0\x08\xec\x5e\x18\x24\x42\x29\x04\x78\xbb\x24\x88\xcb\xc1\x50\x6a\x07\x0f\x4b\x92\x58\x2a\x11\x48\x9a\x51\x77\xe8\x79\x83\x49\xe8\x5f\xf6\x1a\x1d\xe7\xaf\x9d\x48\xda\x0d\xc3\xdf\xaf\x43\x39\xf3\xef\x92\x32\xef\x85\x6d\x12\xe2\xcb\x80\x94\x85\xd2\xd7\x30\x27\xa7\x21\x2e\xaa\x69\x4b\x9a\x63\x98\x40\x30\xf7\xe1\x6b\x48\xad\xfe\x48\xdd\xb2\x2f\x42\x8c\xe2\x32\x61\x89\xa3\x74\x8b\xb8\xf4\xe3\xa6\x88\xab\x7a\xb8\x8d\xbc\x58\xe7\x13\xc8\xc1\x02\x4d\x87\xdb\x49\xa7\x7f\xe5\x77\x88\x88\xc7\x45\x19\x20\x44\x25\x22\x90\xe9\x1d\x12\x2e\x39\x97\xc8\x39\xd7\xbb\x92\x5d\x4a\x60\xeb\x15\xab\xbd\x83\x7d\xa1\x64\x70\x18\x6a\x58\xf8\x6e\x96\x2b\xa4\x2d\x41\xd8\xa0\x1f\x4a\x39\x4c\xb1\x8a\x83\x26\xc6\x6a\x29\x70\x64\xe4\xac\x0d\x6b\xb1\x21\xd7\x31\xca\x45\x29\x78\x28\xbf\x0d\x0b\x5d\xf0\xc1\x8e\x9e\xa6\xd6\xd8\x16\x94\x4f\x83\x68\x10\xfa\x13\xa9\xcf\x0d\x1e\xf0\xd2\xc0\xb0\xb1\x6c\x52\xd2\xc2\x75\x52\x33\x3e\x52\xc8\x96\x4a\xe5\xef\x7b\x78\x43\x24\x92\xb0\xd8\xa8\x3b\xa2\xe3\x96\xaa\xf0\x4e\xb9\xc0\x2d\xaa\xf0\x7f\x8f\xd2\xfb\x88\xb9\x43\xcf\xff\x55\xbd\xb7\xba\x61\x7f\x5a\xc5\x15\xa6\xdd\x65\x2d\xc8\xd5\xe8\xe6\x8a\xca\x3e\x4e\x63\xd1\xc3\x05\xd7\x08\xf0\xd5\x84\xc0\xa1\x3f\x7f\x62\x06\xba\x14\xb4\x59\x7b\x1b\x79\x78\x5a\x92\x87\x83\x10\x02\x48\xd1\xc2\xfd\x85\x12\xdf\x04\xe6\x60\xd4\xd6\x28\x75\xc9\x44\xb2\x41\x24\xb6\x86\x5d\xbb\x4c\x0c\x40\xdf\xaa\xea\xe4\x17\xa1\x9a\xea\xb0\x58\xf3\xd5\x2c\x10\xfe\x20\x59\x52\x57\xd9\x9d\x36\xc4\x55\xa6\xe6\x5e\x03\xa9\xfe\x26\x89\x5c\xb0\xc1\x03\x8d\xae\x73\x01\x31\x1c\x11\x17\xd0\x3f\x21\x18\xcd\xc9\x51\xb1\x41\x25\xf9\xd5\x53\xc8\x11\x7c\x4e\xde\x86\x20\x20\x92\xcc\x2a\x47\x70\x85\x1b\xaf\x3b\x45\xe0\x15\xe1\x14\x30\x80\x12\xdc\x14\xdc\x14\x2d\xca\x35\x13\xa0\xc2\x9c\x5c\x9b\x60\xf9\xdf\x52\x3f\xac\x7e\xc2\x32\x1c\x3c\xd2\x13\xea\x8e\x4c\x09\xc9\xf7\x10\x11\x72\x8c\x12\xed\x17\x13\x30\xb1\x69\x04\x38\x7a\x64\x56\x54\x14\x79\x9f\x3a\x63\xcc\xec\x28\x5b\x3e\xab\x77\x31\x27\xaf\x43\xac\x4e\x0d\x14\x38\x0c\x65\x07\xa5\x49\xd5\x38\x8d\xd5\x0e\x2a\x00\x4a\x7a\x13\xb4\x31\x62\x80\xa3\xb6\x8e\x45\xcb\x54\xaa\x53\xaf\xb4\x91\x55\x01\x30\x3c\xdf\x62\x5b\x45\x8b\x33\x8b\xb5\xc5\xf9\x7d\xe8\x3c\x0f\x89\xe1\xce\x7c\x77\x8e\x78\xfe\x59\x2b\x6a\x57\x4b\xc9\xf0\xdf\x84\xa5\x73\xa7\xd6\xdd\xa0\x68\xfc\xd5\xc4\x63\x93\x8f\xdb\x4c\xb3\x33\x1a\x4d\x31\xf1\x0b\x0f\x20\x82\x37\xa1\x44\xa5\x4f\x6d\x52\xc4\x2d\xcc\xb3\x73\xf2\xaa\x78\xb6\x10\x12\x7e\x25\x10\xab\x8a\x6f\x03\xa9\xde\xf2\x38\x2c\x2e\xe5\x1c\x59\x7c\x59\x61\xe4\xf8\xee\xe7\xfc\x63\xf1\x19\xd2\xf7\x7a\x07\x83\x7c\x49\xdf\x87\x45\xbd\x3a\x6e\xca\xaf\x54\xe5\x33\x05\xbc\x0c\x4c\xcd\xdd\xaa\x08\xd5\xe8\xc5\x0b\x5c\x3c\xe5\xb9\xb9\xad\xe7\x2b\xf3\x96\x14\x5d\x4a\x84\x8b\x34\xe9\x51\xf0\xff\xa5\xd5\x3a\x4b\x3f\xdb\xf7\xd1\xaf\xec\x13\xba\x0d\xa1\xd3\x6e\x91\x8d\xe5\x65\xe8\x34\x4a\xbc\x1f\xa6\xd5\xd8\xbd\x45\x5a\x46\xd7\x45\x59\x11\x5d\xf7\x32\x54\x05\x8b\xb9\xbc\x95\xb9\x60\xcc\xfd\xab\xfd\xd8\xf3\x0d\xc0\x6c\x28\x26\x88\xac\x7b\xc7\xe7\xfe\x95\x17\xaf\xa2\x62\xcb\x79\x86\x55\x7e\xb7\xbf\x91\x2e\x37\xda\xa7\x72\xe8\xd7\xa2\xa8\x5d\x79\xe8\x9b\x20\x55\x5a\x9a\xdd\x32\xff\x94\xdb\x36\x60\xc5\xef\x35\xe8\x78\x5e\xe4\x8b\xc9\x9c\x7f\xf8\x51\xe6\x54\x8f\x17\xff\x01\x93\xcc\x79\x02\x2c\x73\x76\x1e\x40\xd2\xf1\x45\x25\x25\x71\x25\x34\xc6\xe1\x80\xa6\x22\x6e\x93\x27\xb7\x1a\xa5\x6f\xc3\xcd\xe6\x84\x66\x70\x47\x6a\x0b\x25\xd4\x3c\x0f\xf4\x71\xcf\x56\x8e\xa8\xac\x81\xd5\x5e\x76\x6a\xbd\x18\xff\xe7\x7f\x1b\x15\xf0\x83\xb0\xf5\x63\x6f\x61\xf9\x7c\x08\x45\x9a\x20\x15\x7b\xa3\x32\x86\x66\x99\x3a\xd4\x5b\xd0\x50\x92\x2b\x2f\x43\x22\x54\xf8\xd6\x99\xd0\xcf\x90\x0a\x05\xf2\xf7\x42\xfd\x56\x09\xa9\x4c\x98\xb5\xce\xe5\x8c\x44\x70\x67\x68\xae\x61\xd9\x05\x21\x95\x63\xa5\x9d\xe2\x58\x69\x9a\xb5\xd0\x37\x35\x92\x76\x62\x5f\x75\xec\xf3\x32\x03\x4d\x7d\x15\xe4\xce\xb2\x1c\x82\xa7\x19\x5a\x95\xae\xb2\x76\x8b\x51\x5f\x85\x7a\x7e\x53\x59\x12\x38\xa4\x4e\x94\xa1\x33\xb4\x43\x35\xc5\xe9\xc7\x2a\xe3\x18\x0b\x31\xe7\x11\x96\x3e\x72\x9d\x34\x93\x02\x69\xe0\x1c\x92\x14\x51\x21\xd6\x05\x47\x42\x29\x42\x4c\x94\x07\x8b\x18\x19\x86\x2d\x55\x05\x63\x46\x93\x7c\x97\x6d\xbc\x48\x52\xd7\xf5\x93\xaa\x9c\x5b\x42\x22\x8f\x57\xbd\x28\x1e\x4c\x53\x21\x7c\x9e\x74\xa8\x35\x47\x6a\xb3\x93\x4c\x8e\xb7\x01\xca\x12\xd4\x8d\xbb\x93\x42\x02\x0e\xa2\xc1\x2a\xf0\xc4\xcc\x00\xe3\xfe\x70\xb8\xbc\x6c\x03\x7f\x5c\x3c\x85\x00\x9b\x44\xba\x9f\xb5\x97\x41\x43\x72\x3d\x89\x79\x41\x3a\x11\x3a\xe4\xe2\x89\x8c\x6c\x98\x0d\x0f\x49\x04\x2c\xab\x84\xd7\xb7\x2e\x6c\x5e\x80\x63\x92\x99\x65\x9d\x0e\x91\xef\xd6\x19\xf1\xc1\xad\x04\x45\xd2\x9f\x3f\xb9\xc5\xac\xfe\xa8\x1f\xdb\x39\xf2\xc9\x1b\xb4\x60\xda\x6e\x26\x7b\x2e\x8a\xf0\xc4\x6b\x13\xfc\xac\x2d\xf6\x59\x0f\x3a\x92\x2f\xec\x98\x36\xb6\x5c\x65\x24\xc8\x5a\xd8\x45\x65\xa5\x06\x4c\x44\xdb\x88\xc4\x92\x07\x0b\x75\xa0\xe3\x65\x24\x30\x81\xb6\xc8\xb2\xf0\x8b\xe6\xb2\x30\x23\xf1\x5f\x70\x62\xa1\x46\xce\xb2\xe2\x75\xb9\x8f\x52\xc5\xa8\xe9\x19\xe5\x7c\xf7\x91\x49\xf6\xf4\xe6\x43\xcf\xb7\xa6\x96\xd1\x4e\xd6\xf0\x80\x56\x9f\x74\x29\xe0\x65\x34\xf1\xf1\x04\x15\x49\x5c\x90\x91\x38\xab\x90\xb7\x38\x2b\x89\x1b\x26\x57\x86\x79\xb6\x4d\x24\x29\xc5\x8e\xc9\xe3\x9e\x17\xb0\xde\x82\xdd\xef\x2d\x78\xab\x1d\x40\x19\x93\x6e\x10\x3b\xde\xa3\x72\xf9\x31\x24\xa2\x65\xbb\x97\x61\xcd\x0e\x65\xa0\xef\x70\x21\x08\x5c\x76\x30\xae\xfc\x18\x77\xb7\xe3\x79\x9e\x24\x7a\xbc\x85\x83\xd6\x8e\x71\xf7\x9b\x0d\x95\xfe\x9c\xdb\x9c\x4d\x73\x54\x64\xe5\x33\x1a\xfa\xb3\xfc\x12\x8f\xc7\x4b\x29\x0c\x28\x23\x8b\x3a\x88\x90\x34\x6e\xac\x30\xc7\xdc\xb4\xce\x9b\x70\xb8\x45\x4e\x58\xc4\x69\xe2\xab\xd5\x2d\xce\xfa\x4f\x6f\x6a\x1f\xfa\x34\xf3\xcb\xf6\x17\x1d\xab\x93\x1f\x72\x9f\x4b\x06\x7f\x9c\x39\x0f\x87\x70\x82\x6c\xfe\x5b\xe6\x3c\x78\x02\xd7\xcd\xb5\x68\xaf\xbb\x58\x16\xc5\xe4\x79\x31\x23\x2c\x2d\x55\xd0\xa1\x73\x41\x84\x59\x2b\xbf\x78\x5b\x89\x66\xaf\x63\xea\x79\xa4\xcf\xbb\x1b\x24\x9a\xb7\x37\x48\x44\x07\x5b\x96\x92\x85\x69\x65\xd1\x8f\xb2\x46\x59\x64\x55\xa7\x04\x39\xda\x91\x4a\x5e\x30\xc4\xe4\x05\x74\x07\xbd\x6c\xd9\x13\x2c\x32\x4d\x39\x72\xad\x33\x01\x69\xa6\x8a\x52\xbd\xdb\x62\x07\xbc\xce\x72\x3b\xe0\x07\x81\xf5\x39\x28\xea\xbd\x62\x74\x20\xa9\xaf\x82\x21\xd4\x80\xb1\xc7\x73\xf1\x2b\x3d\xa6\xea\xc0\xae\x85\x17\xde\xc0\x96\x36\xeb\x17\x75\xb0\x24\xbf\x8b\x25\x1d\x97\x2c\xe9\x6d\x46\x58\xc1\x80\xbe\xd5\xee\xc7\xc5\xfd\x93\xf2\xbe\x18\xe1\x87\x1e\x68\x26\x36\x46\x56\x23\x3f\xa3\xb2\x1a\xf9\x6b\xe7\x55\x7e\xe6\x97\xfc\x2c\xcd\x88\x6b\x42\x50\xe5\x69\x56\x1f\xb9\x9a\x5a\xd5\x33\xcd\xd3\x68\x85\xa7\xbd\xab\xf1\xb4\x83\xed\x3c\xed\x3c\x33\x47\xef\x14\x4f\x3b\xd0\x3c\xed\x22\x33\x81\x70\x67\x4f\xcd\x57\x01\x94\xaa\xb5\x2a\x21\x0a\xeb\xa2\x1d\x64\x64\x0f\x5f\xfa\x0b\xb9\x9f\x22\x36\x93\x36\x6b\x8e\xa2\x35\xdf\xff\x1b\x24\xf8\xb3\x86\x04\x1f\xfd\xa2\xf4\x7e\x76\xa3\xf4\xfe\xba\x83\x92\x97\x29\x67\x15\xde\xc6\x0a\x53\x27\xce\x1d\xb4\x4d\x05\x10\x59\xee\x02\x6b\x3d\x9f\xc5\x10\x40\x2c\x71\xed\xc8\x27\x01\xba\x59\x4c\xb6\xc8\x98\xa0\xfd\xf3\x36\xad\x42\x18\xb6\x36\xcf\xc0\x18\x47\x68\xe3\x55\x7a\xb0\x32\x6e\x60\xb5\x76\x0e\x97\x59\x35\xdc\x92\x8f\x4a\x3b\x53\x02\xff\xaa\xc8\xfa\x3d\x93\x73\x6f\x15\x59\xd9\x2d\x44\xd6\xa3\x0c\x26\x10\x99\x40\x5c\x47\xa2\xde\x59\x0c\x95\x23\x0d\x70\xcd\xd1\xaf\x48\x35\x27\x94\xf9\x61\x6f\xee\x5f\xf5\x26\x31\x2f\xbe\x3c\xb7\xd3\xe9\x43\xd5\xbf\xa8\xbb\x3f\x25\x33\x5d\x64\xf5\x93\x9b\x72\xcc\xca\x5d\x2d\x3f\xa9\xb4\xd6\x58\x32\x61\x07\x6b\x26\x20\xf5\xbf\x23\x2c\x7a\xf2\xf7\xbf\xdf\x11\x16\x9b\xff\xfc\x79\x14\x93\x14\x01\xc7\x48\x66\xf1\xca\xa8\x6d\xa6\xc4\x2f\x37\x5e\x2c\x43\x5f\xf8\x83\x85\x1f\xa5\x3d\xe3\x2e\x95\xc2\x00\xd9\x45\xa2\x61\xc2\xa9\xfa\xb9\x63\xb6\x60\x61\x21\x65\xc8\x37\x4b\x5b\xe2\x3e\x52\xe1\x54\xcd\xf0\x6b\xf1\x07\xa3\x24\x3e\x64\x8e\x64\xfa\x6b\x78\x71\x03\xd3\x7c\x75\x83\x34\xf5\xfc\x06\xa6\xfc\xbe\xe3\x79\x1e\xd5\xf8\xf9\x16\x42\x56\xab\x30\x55\x9e\xdc\xdb\x6d\xcf\xb7\xb9\x18\xd2\x90\xbc\xc8\x08\xb7\xdc\x55\xc3\xa0\x2b\x72\x71\xcc\xa2\x0f\x35\x95\x7c\x93\xe9\x1c\xb8\x1f\x3b\xa9\x88\x62\xc0\x91\x64\xc1\x65\xd9\xc9\xb6\xf3\x71\x2c\xb6\x75\x2a\x6e\x28\x34\x17\x59\xee\x6a\x5d\x58\x7e\x22\x5f\x27\x43\x37\x4d\xb3\x71\xee\x57\xb5\x12\xf6\x16\x39\xa1\x96\xe0\xb8\x03\x73\x32\xe5\x60\x08\xca\x8e\x23\xcf\xbf\xc4\x54\xfa\x42\x55\x24\xdc\x38\x2b\xe4\x7e\x48\xd5\x62\x76\x78\x5f\xd6\x41\x8e\x86\xe4\x4d\xa6\xf8\xbe\x32\x42\xf2\xc1\xc3\x2d\xcb\x5d\xe2\xcd\x5b\x5d\x05\xcd\xee\x19\x77\x55\x0e\x04\xf4\x3c\xf7\x2b\x2c\xe9\x53\xa7\xf1\x82\x5b\x8c\x23\x9f\x9e\x8f\x48\xea\x10\x81\x49\xd0\x8f\x80\x3a\xc2\x62\x4b\x70\x0b\xa9\x0a\x91\x70\xf8\x4b\xa2\x95\xaf\x45\xab\xa0\x10\xa4\xfc\xdb\xbf\xef\xab\x77\xb7\x6d\x08\xae\x50\xaf\x89\xe3\x48\x07\x10\xcb\x5f\x95\x58\xfe\x4a\x61\xf9\x9f\xd9\xa5\x42\x56\xdb\x2c\x3b\x27\x05\xb3\x14\x85\x8d\x0f\x19\x4a\x26\xef\xb3\x86\x98\x56\x11\x65\x8e\x33\x73\xf4\x5c\x6a\xd1\xb6\x16\xd0\xe4\x95\xab\xae\x4e\x32\x73\xf4\x22\x53\xe6\x9a\x14\xba\x32\xfe\x2a\x48\xc6\x50\x3c\x36\x59\x6b\x98\xa9\x82\x8b\x4e\x33\x61\x48\x09\x3b\x76\xe7\xe5\x59\x8c\xe6\x44\x3b\xc3\xe1\xff\x28\x0d\xc8\x1d\x24\xaf\x57\xbb\x52\x2e\xab\x25\x19\xfc\x9c\x11\x74\x43\x47\xfa\x67\xcf\xc9\xc7\x0c\x22\xe0\x16\x9b\x15\x2e\x84\xb9\x10\xb0\x36\xe1\xcb\x16\x49\x41\xca\x08\xb1\x12\xea\xcf\x55\xe8\xdc\x31\x0a\x0e\x6c\xaa\x04\x87\x3d\xc0\x20\xb6\x10\x98\xfc\x33\xc7\xec\x36\xec\xc1\xf6\xf3\x22\x97\x72\xaf\x57\x15\x0f\x36\x1f\x0e\x66\x3e\xf5\xaa\xea\xf4\x51\x15\xcc\x7a\x12\xd4\x04\x65\x49\xaf\xd2\x16\x6f\xe4\x2f\xec\x12\x37\x84\x21\xe8\xe0\xb6\x20\xc4\x1a\x52\x1a\x1f\xd5\xe1\x9f\x72\xc1\xc2\x76\x3b\xcd\x76\x04\x1d\x2c\x5d\x78\x9e\x10\x7f\x64\x3c\x47\x59\x8f\x28\xb1\xc5\x34\x6c\x75\xc3\xc8\x6d\x1b\x7b\x61\xad\x54\xd5\x9c\x7c\xca\xe4\x4a\x4f\x20\xc0\xc0\xd2\x4f\x21\x94\xee\x92\xc0\xad\xd7\x30\x09\xf3\xfb\xe5\x19\x39\x70\xeb\x0c\xe2\xb0\xb4\x98\x6c\x2c\x88\x06\x14\xf5\x79\xf1\xa8\x1c\x35\xce\x47\x7d\x9d\x01\xc6\xf0\xbb\xb8\xdf\xf9\x63\x5d\xdf\xeb\x4a\x82\x70\xad\xf3\xfe\x4d\xe2\x6a\x79\xbe\xd9\x38\xf4\x7e\xa0\xd8\xc9\xcb\x80\x10\xe1\xdc\xc1\xc8\xc5\x1d\xc9\xda\xc4\x3a\xf7\x71\x4d\x46\xdb\xdc\xca\x1e\x54\x8d\x45\xfb\x71\x18\xd2\x65\xe2\xf7\x68\x18\xea\x03\x2f\xc3\xfc\x6a\x6f\x71\x13\xab\xbd\xae\x82\x79\xea\x2f\xe7\x9f\xf9\x32\x81\x4b\xf2\x21\x84\x09\x30\x48\xa4\x50\xa0\xc8\xed\x4b\x65\x86\x9e\xed\x18\x26\x44\x5e\x2d\xa6\xe4\x65\x56\xc6\x94\x44\xb1\xc8\x4f\xde\x74\x8f\xdc\x53\xf6\x6b\xc1\xe3\x68\x6a\x98\x20\xbc\x1b\x4e\xeb\xa9\xf5\x2d\x0f\x75\x75\x9b\x25\x0d\x6b\xa8\xad\x4c\x4a\xf2\x9f\x81\x1b\x87\xe9\x42\xe5\x34\xd4\x7a\x46\x45\xca\xce\xbd\x07\xf2\x83\x31\x3d\x71\xee\x15\x13\xe7\xe5\x02\x44\xf2\xd6\x22\x23\x14\x53\x9e\xad\x50\x34\x3a\x40\x6a\xb8\xa9\xbf\xf6\xaa\x17\x85\x44\x5f\xb8\x29\x6c\x24\x2b\xb9\xfd\xcc\xff\x3d\xb3\xad\x4c\xac\x9a\x68\x2b\x70\xdc\x5a\xe1\xf2\x5f\x58\x5d\xed\x28\xfd\x9f\x58\xdc\x5c\x8f\x6b\xd2\xf7\x5a\xb3\x89\xef\x7b\x8c\xba\x55\x67\xd6\x20\x17\x19\xa4\x2e\xee\x75\x9b\x2e\x8f\xd1\x3a\xf3\xfb\x70\x14\xd9\xc3\xdf\x8f\xb1\xbc\xd1\x88\x63\x75\xa3\xd4\xeb\x72\xe0\xcd\x3d\x77\xf9\x3f\xa3\x9f\xff\xe4\x3f\xff\x19\x29\x07\x5e\xaa\x40\x5e\xaa\x21\x94\xfb\xd4\x30\xc1\x6d\xed\x42\x89\x5d\x3c\x5e\x25\x28\x72\xa1\xc1\x28\xf0\xb6\xa6\x0a\xbe\x24\xbe\x07\x0f\x60\xe7\x11\x7c\xa1\x24\xf5\x54\xbe\x66\x75\xe6\xf1\x6f\x41\x1b\xbe\x7d\x67\xa3\x72\x67\xa9\xa7\xb7\x36\xcd\xb7\x56\xe0\xd6\xfa\xb7\xc6\x1b\x70\x3d\x42\xff\x0a\xec\xf9\xb7\x4c\xba\x31\xbf\xbf\x1a\x89\xfe\x03\x4b\x5d\x58\x43\xca\x2f\xf9\x97\x71\x29\x6e\x03\xe9\x4a\x1d\x8f\x49\xc7\xf3\x22\x46\xaa\xe3\x79\x1e\x83\x95\x78\x52\x99\x7a\xba\x86\xd0\xd3\xe5\xa9\x33\xaf\x2d\x2d\xf8\x0e\x1e\xea\x57\x22\x53\xda\x63\x94\xaa\x41\x3d\x35\x2f\xa4\xdc\x16\xd5\xea\xb5\x25\x51\x78\x9b\xcb\x56\xfd\x79\xab\xbf\x96\x6a\x52\xb7\xde\x97\x31\x16\x6d\x47\x01\xbf\x36\x6d\xaa\x4f\x46\x36\x9c\x96\x5a\x6d\x20\xbc\x54\x9f\xbc\xe6\x62\x56\x8b\x4e\xb5\x1f\x55\xab\xdc\x1d\x8e\xca\xdd\xa1\x92\xeb\xa1\xd5\xec\x48\xca\x34\xdb\x9d\x59\x73\xef\x1f\xf4\x4b\x15\x16\x6b\x5a\x94\xb7\x3b\xa6\xfe\x6b\x6e\xa7\x15\x27\x53\xae\x9d\x4c\xb9\x76\x32\x3d\x0d\x31\x3b\x7b\xe1\x3c\x8a\xd2\xeb\x6b\xf0\x6b\xce\xa3\xbe\xa5\x7c\x24\x61\x33\x78\xe0\xf6\x2e\x98\xbc\xdb\x05\x33\xf3\x30\xf6\x20\xcd\xf7\xa4\xdf\xdc\x93\x36\xaf\x2b\x3a\xec\x95\xa1\x0f\xd8\x91\xe7\x91\xc8\xd4\xa5\x15\x17\x8a\xf9\x2c\x0d\x13\x66\xcd\xfe\x5a\x82\x58\x0b\x9f\xe8\x7c\x43\x8e\x62\x22\xcc\x51\x63\x5d\xcb\x05\x5f\x78\x2d\xf4\x09\x1d\xb0\xf2\x14\x80\x15\x1b\x9d\xfa\xdf\xfe\xe5\xee\x76\xeb\x7d\xd9\xca\x99\x1f\x93\xa1\x55\x84\xf2\xbe\x87\x0e\xdb\x4d\x7e\xa1\xdd\x77\xeb\x5c\xb0\x12\x8c\xdb\x28\xd7\x71\xfb\x30\x61\x3f\x27\x81\xcb\x0e\x12\x96\x5b\xb4\xa6\x6d\xe2\x46\x77\x18\x71\x75\xca\x15\xbe\xb7\x17\xc2\xd2\x83\x39\x99\xa9\x4f\xdd\xcc\xbc\xa5\xc3\x89\x37\x43\x01\xde\x27\x72\x86\x2b\xcf\x31\x16\x62\xf0\xc8\x80\xab\x2d\xa2\x4f\x85\xf8\x44\x1b\x04\x65\x53\x9d\x78\x90\x33\xaa\xdc\x11\x77\xee\xe9\xd2\x43\x97\x5d\xc0\x5b\x04\xd6\xe6\xa7\x73\xbb\xdb\x5a\x3e\xac\xb6\x1c\x6f\x6b\x79\xbf\x76\x02\xdb\xf6\x79\x95\xbc\x08\x8e\xb0\xe8\x43\x08\x1c\x61\xb1\x43\x88\xe5\xd5\xe7\x67\xd5\x15\x66\xde\xa6\xc9\xbc\x55\xcd\x8e\x73\x8f\xc7\x31\xf9\x23\x24\xc2\x83\x17\xa1\x2e\x9a\x73\xe9\xe9\x2c\x03\xbc\xd0\xec\x28\x66\x3b\x6d\x68\xa6\xdd\x7d\x8c\x55\x1f\xa9\xee\xe3\x01\x50\x3b\x5d\x9b\x10\xb4\xf6\x71\x8b\x13\x75\x75\x80\xa0\xab\xd5\xc5\xb0\xeb\x61\x45\xcd\x68\x74\x49\xae\x3c\x68\xf3\xc9\xd5\x56\x41\x30\x26\x74\x20\x38\xfa\x29\x18\x48\x19\xa1\x92\x8d\xa7\xf4\x35\xfd\xaa\x72\x39\x1e\x7a\x3a\x79\xfc\xa9\xd4\x0b\xb7\x28\xc7\x85\xa0\x47\x43\x32\x61\x15\x73\xdf\x6b\xee\x67\x81\xbf\xd2\x99\x43\x95\x99\xe1\x62\x2b\xc0\xd6\x4e\x4c\x1e\xf6\x8c\xbb\x2b\x4f\xf7\x77\xea\x01\xe6\xf5\x48\x1d\x49\xca\x0d\x4c\x20\xe1\x1b\xb6\xf1\x1e\x0b\xef\x19\x35\x03\xff\x42\x2e\x63\xf3\x44\x8c\x86\xe4\xd0\x2b\xa7\x97\x2a\xc3\x7d\xe7\x8b\xd5\x33\x26\x51\x33\x62\x26\xbe\xc8\x17\xea\x99\x06\xc6\xb5\x09\xe7\x37\x90\x8d\xe3\x8e\xe7\xb9\xa1\xfd\xa4\xe3\x79\x7e\x3a\xfd\xcd\xd3\xa5\x5a\xae\x6f\xb9\x84\x3c\x5e\x55\x57\xb0\x00\xca\x73\x3c\x1d\x02\x0d\xb2\x3a\x61\x96\x07\xcc\x33\x81\x79\xe4\x9b\x67\x42\x64\x42\xd1\xfa\x40\xd7\x15\xd0\x2f\xdc\xd7\x2f\x9c\xd7\x5e\x10\x95\x17\xc6\x98\x03\xa0\xda\xf9\x71\xad\x6d\xee\xe8\x70\xe6\xb5\x26\x29\xc0\xb8\x53\xc0\xea\x29\xa7\xaa\x7c\x8a\x80\x40\x5e\x2d\x01\x0b\x78\x5c\xa0\x91\xad\x3f\x3a\x23\xc6\xa9\xbf\xca\xb3\xd1\xca\x91\x56\x13\x10\xf0\x21\xc1\xac\x5f\xc6\xd8\x0b\x44\xf9\x70\x3a\x51\x59\x92\x80\x39\x93\x8d\xa0\x80\xa6\xb5\x63\x62\x51\x04\xd5\x4b\x72\xed\x01\xb5\xd8\x0a\x28\x56\x22\xb0\xae\x10\x8b\xa9\x45\xfb\x55\xb4\x2d\x16\xb8\x96\x90\xa3\x4d\xd6\x37\x5e\xe9\x4a\x87\xbd\x3c\xea\xb1\x14\xec\xaa\x66\x72\x85\x2f\x25\xdb\xcd\x9d\xf3\x75\xa4\xb2\x65\xb4\x99\xc6\x6a\xb4\xad\x74\xd7\xa9\xd1\x25\xe4\xe7\xf9\xb1\x15\x6c\x6d\xf6\x41\xf9\x1a\x7e\xdd\xb4\x94\xa1\x4f\xf8\xbe\x47\x76\x7e\x97\x9a\xaa\x89\x62\x0e\x74\x50\x1e\x45\x71\x30\xb6\x44\x6e\xfe\xdc\xd3\x67\x65\x05\xa8\x14\x69\x60\x56\x9e\xb6\x1b\x16\x90\x12\x7a\x26\xa8\x0c\xd6\x2b\x12\x78\x60\xec\xe7\xe5\x26\xf3\xa6\x71\xd1\x34\x51\x4d\x77\xcd\xd6\x5d\xb9\x24\x53\x0f\x62\xac\x2a\x0a\x97\xe4\x42\x72\x5b\x0a\xac\x94\x98\xf7\x94\x60\x35\x7b\x64\x98\xf0\xae\x8e\x82\x6d\x6a\x48\x55\xa8\x75\xc3\x60\x89\x76\x79\x57\x90\x21\xe0\x7f\xa6\xd1\x62\xb8\x9f\x04\x97\xa5\xbc\x5e\x23\x72\xb1\x47\xc3\x9e\x54\x05\xda\x4c\x20\xf8\x74\x20\x75\x35\x8f\xc7\xcb\x6a\xb3\xaf\x75\xf7\xfa\xc7\xca\x9f\xd2\x62\x6f\x40\xa7\xd1\x7c\xa5\x8c\xd5\x96\x7b\x72\x43\xb4\x42\x31\x81\xfc\x2c\xa2\xc3\x2a\xdf\x31\xf7\x81\x17\xd0\x30\x9e\xf6\xaa\x17\x9a\x5b\x6d\xf9\x62\xd4\x45\x31\x39\x48\x57\x83\x4d\x9b\xf7\x9e\x57\x7f\xae\xf3\x60\xd4\x69\x79\x8d\x94\xbb\x61\x9c\xe8\x73\x5c\xde\xea\x17\xd0\xb6\xd4\xb1\x77\x95\x77\x2a\xda\x9b\x4c\xe2\xb8\xc2\x89\xfd\xaa\x0f\xdd\x4d\x7b\xa7\x57\xb8\x10\xb2\xe0\xed\x36\x31\xa8\x2a\x05\x1d\x74\x36\x64\x6f\x90\x6d\xef\x72\xbf\x77\x15\xa7\xbd\x24\xd5\x3f\x56\x34\x12\x3d\x11\xf7\x54\x35\xd9\x1a\xf5\x18\xc9\x45\x79\xd5\x1a\xb7\x5c\x63\x95\x97\x94\xcc\xc9\x5b\x4f\x15\xe2\xaa\x3a\x25\xc6\xd1\x24\xe0\x0b\x45\x42\xe8\x63\xfb\x92\x12\x37\x31\xc1\x3d\xb1\x8d\xb1\x1a\x2d\xa7\xba\x72\xea\x47\x5b\x74\x9f\x36\xad\xb6\x77\x63\x50\x6a\x84\x01\xfd\xc7\x61\x59\x1e\xe7\xfb\x96\x75\xac\x49\xa8\xaf\x3b\x15\x27\x95\x0f\xe3\x72\x33\x58\xb8\x55\xdb\xb8\xd9\x2f\x65\x23\xe6\x1b\x57\xf2\x7b\x73\x25\xd5\x72\x19\x35\xab\xd3\x5f\x3d\xc6\x81\x1f\xfa\x42\xc7\x6c\xaf\x4d\xf8\xd0\xb9\x1d\x61\x46\x22\xf3\xae\xf1\x77\x5d\xd6\x57\xe5\x28\xc1\x7c\xe4\x2f\xbc\x16\x2f\xee\x6a\xba\xcf\x5a\xfe\x64\xac\xe4\x63\xf8\x5e\x20\x30\xf9\xa7\x70\x7e\xd1\xd5\xb6\x8a\xac\x92\x87\x1b\x55\x67\x18\xbd\x4d\x23\x61\xff\x62\xaf\x73\xf2\xc1\x03\xf4\x3c\xc7\x82\x41\xf5\x23\x69\x25\x4a\x2a\x9c\x7c\xd5\x61\xd1\x7d\x9f\x2a\x37\x7e\xc3\xf9\x5f\x86\x5d\x9a\x4a\x1e\xa2\x4f\x3f\xbe\xf9\xbc\x6d\x99\x2e\x29\x09\x93\xcd\x94\x3f\xad\xa5\x83\x6b\x47\xfb\x99\xa7\x3c\x1f\xe0\x95\xa7\xcc\xc7\xef\xb7\xa0\xd1\x7f\x67\xfc\x6f\x31\xd9\x8a\x6a\x5c\xc5\xb1\x0a\x3a\x1d\x79\x28\x34\x26\x98\xc7\x7e\xbc\xa9\x08\xab\xe7\x28\xb3\x62\x0b\xb6\x6a\xc1\x16\xec\x42\x57\xce\x56\xbd\x60\x0a\x3a\x82\x06\x90\x0f\xbf\xea\xee\x5d\x4f\x0a\x53\x95\xfd\x3f\x04\x3e\x92\x70\x53\xa2\x05\x26\xda\x20\xaf\x3d\xe0\xaa\xb6\x6a\x9d\x03\x94\x66\x9c\xe7\x9e\x9c\x52\xdf\x94\xf2\x05\x89\x46\xa7\x82\xcc\xc9\x81\x7e\xcb\xb4\x2f\x44\x69\x3a\x5c\x9b\xf0\xb9\x15\x00\x13\x4e\x56\x1c\x41\x41\x07\xc7\xbe\xa9\xe9\x00\x1c\xaa\x55\xa0\xc4\x86\x15\x08\x1d\x22\x8a\x98\x78\xe5\xe2\xd0\xdf\x72\x62\x4f\x67\x6b\xe5\xc8\xb2\xd5\x43\x85\xed\xad\xb5\x67\x0a\x56\xb4\x35\x41\xb9\x37\xe9\x98\xbd\x7c\xfd\xf2\x53\x43\x7b\x4e\x3e\x17\x3c\xbc\x84\xbd\x72\x91\xda\x03\x5a\xd4\xe6\xbd\xf7\xf2\x58\xe9\x08\xcb\xcf\xab\x08\x9a\xb4\xcd\x66\x22\xda\x6d\x26\xa8\x54\xac\x4d\xf8\xe8\x55\x33\xec\x7f\xaa\xaf\xf5\x46\xca\x88\x1c\x42\x73\x0f\xef\xfa\x60\x45\xcd\xf5\x8d\xd1\x8a\x02\xee\xeb\x35\x7c\xe9\xd0\xe8\x72\xd7\xa9\x97\x5b\x14\x39\x3c\x8e\x17\x10\xa9\x1d\xf8\xe2\xc1\x25\x35\xab\x25\x93\x83\x09\xe1\x79\x89\x2b\xfe\xac\x38\xbc\xd2\xf9\xee\x3e\x79\xb9\xa7\x4f\xc5\x6c\x4e\xbd\xa9\xdf\xc3\x7f\x07\xcb\x20\x0c\xe3\x95\xbe\xd0\x1f\xa0\x71\x19\x79\xb1\x88\x97\xbd\x45\xdd\x09\x5f\x9d\x64\xa1\xa8\xb3\xee\x18\xee\xab\x89\x25\x98\x4d\x88\xfa\x55\x72\xc5\x75\xe0\xe9\x03\x2d\x4b\xff\x68\x31\x93\x77\x38\x35\x14\x84\xa8\x3b\xca\xea\xa5\x87\x15\x08\xd9\x67\xf9\xcf\x1e\x86\x29\x17\x13\xbc\x65\xbf\x73\xd5\xc9\x50\xc2\x07\xce\x9f\xf7\x31\xde\x6a\x26\x16\xe1\x61\xcc\x0d\x13\x44\xdf\xf1\x38\xf8\x7d\xa7\xcf\x21\xed\xff\x17\x4b\x63\xbb\x54\x67\xe5\xfa\x00\xfa\x50\x46\xac\xcd\x76\xe9\xac\x20\x39\xb4\xf3\x83\x34\xa8\x16\x11\x85\xcd\x86\xff\x09\xf9\x69\x57\x7e\xbb\x64\xdd\xff\x46\xf9\xa9\x6b\x8c\x0d\xf9\x29\xe8\xab\xcc\x8e\x86\x09\x71\xd7\xaa\xf5\x1a\x47\x6f\xea\x54\x70\x8b\x82\x7e\x1f\x7d\xac\xb1\x6d\x2d\x00\x7f\x4e\x82\x7e\xdb\x49\x61\xdd\x64\xb8\x33\xbc\xd9\x66\xc8\x0b\x7d\x77\xd2\xef\x36\xbb\x74\x46\xe1\xef\x62\xe2\xee\xfb\x65\x14\xfe\x4c\x83\xe2\x0d\xa6\x94\x32\xfc\x09\x36\x42\xef\x0b\x7f\xa7\x17\x9e\xca\x06\xe6\xf6\x41\x68\x3e\xaa\x3e\x32\xee\x83\x71\x7c\x60\xc0\x73\xa4\xea\x1f\x8a\x7b\x4a\x14\xe8\x51\x81\x8f\x8e\x43\xac\x63\x67\x16\x8f\xa5\x24\x51\x7b\x48\xc7\xe5\x43\x65\x2d\xf4\xea\x2f\x1f\x94\xcf\x95\x59\xd1\xeb\xb1\xab\x7c\xdc\xfd\xf2\x59\x6e\x81\x50\x0f\x76\xab\x13\x12\x3e\xde\x96\x74\x50\x63\x42\xf1\x34\xb7\xf9\x18\xb5\x33\x22\xa4\xea\xaf\x3c\x7d\x56\x64\xea\xea\x74\x26\xa4\x52\x46\xf0\x95\x8c\x90\xe2\x8a\x0c\x0b\x19\x61\x6d\x02\xeb\xb7\x8b\xa7\x3c\x6c\xea\xf6\x35\x20\x6a\xb1\x32\x9d\xd2\x85\x6f\x6b\x4b\x94\x4a\x2b\xf6\xb0\x5d\x88\xd9\xd2\xc7\xae\x2a\xcc\x50\xef\xa6\x08\xd5\x82\x44\xa1\xcb\xec\xbe\x61\x42\xd8\x6f\xca\xc7\xca\x6e\xa1\x2b\xa2\x5f\x29\x9b\xc5\x93\x67\x55\x05\x51\x7f\x55\x52\xa2\x81\xb1\xaf\x2a\x13\xf4\xce\x55\x89\x01\x1c\xb8\xce\x18\x45\x23\xdd\x8b\xe2\x93\xa2\xfd\x58\xa8\x0b\x47\xcb\x4f\x96\x58\x96\x2c\xea\x31\x69\xb8\x7c\x46\x2b\x42\x26\x8b\xc1\xce\xb0\x25\x8e\x5d\x8a\xa4\x7f\x7e\x60\xf5\xdd\xb7\x19\x3a\x47\x39\xc2\xa5\xd4\x73\xa6\x45\x00\x43\xc2\x14\x34\xe5\x73\xbf\x59\x40\x46\xbd\x50\x06\x35\xdc\x19\x6e\x12\xf3\xa2\x4d\x7e\x9e\x86\x6d\x1a\x79\xc5\x75\x23\x6d\x52\xc7\x30\xe5\x35\x91\xb3\xfc\x24\xb5\x23\xa9\x4a\xf6\x0c\x85\x18\x7b\x54\xb9\x46\xbf\x0a\x94\xbf\x73\xf9\xe1\x5b\x44\xb5\x7c\xca\xba\xa0\x49\x7d\x8e\x65\x31\x93\x4d\x51\xad\x88\xb6\x5e\xaf\x89\x5f\xb5\xe4\xd4\xc1\x29\xed\x00\xa7\xf4\xaf\x04\xa7\xd7\xbe\xcf\xcb\x4d\x3d\x0a\xdb\x37\x15\x97\x88\xf5\x21\xca\xe1\x09\xd1\x2c\x53\x68\xe6\xc6\x9e\x24\xb4\x9e\xba\x5a\x72\x4c\x14\xdb\x41\x30\x3a\xa8\x75\x05\xa5\xfe\xfc\x27\xbd\xc7\xb2\x27\xb7\xc4\x91\x05\x93\x42\xc4\xb8\xd8\x82\xb0\x2f\x49\xc9\x95\x0a\xac\xb0\xd8\x11\x74\x91\x03\x5d\x25\xa5\x77\x1c\xa9\xc2\xc7\x3a\x85\xc4\x5f\xf1\x01\x7b\x58\x46\xe5\x96\x1f\x20\x2c\x2a\xda\x38\xf4\xbf\x38\x74\x5e\xe9\xe5\xf6\xa3\xa7\x7f\xf1\xe8\xef\x13\x9f\xdf\x7e\xf4\xec\xaf\x1b\xfd\x79\x5e\xf9\xe6\xf6\xa3\xbf\xfd\xeb\x46\x7f\xab\x4b\xe5\xdc\x7a\x70\xd6\xea\xa9\xfc\xaf\x0d\xfe\xab\x1f\xce\x9e\x97\x54\x0b\x43\x0c\x23\x8b\xee\x59\xf4\xb7\x9a\x5f\x73\x8d\x79\xaa\xca\x43\xba\x7b\xaf\x98\xcc\xb2\xe2\x92\x5f\xcb\xe5\xfd\xb7\xc9\x6f\x93\xdf\x26\x4f\x6b\x79\xbc\x07\x13\xba\x08\xc2\x2b\x03\x8c\x45\x1c\xc5\x2a\x5f\x52\xe9\x5a\xd0\x6f\x38\x88\xea\xb8\xa3\x67\x9a\xe7\xaf\x61\xd1\x2a\x0b\xe4\x7e\xf8\x4e\x64\xb9\xd7\x4d\xa7\xc7\xc7\xa5\x70\xff\x32\x81\x7e\x1f\x94\xd2\x71\xbd\x59\xf5\xb8\x2d\xe5\x04\x4b\x94\xa8\xb1\x54\x07\x24\x17\x28\x6a\xb0\xef\xcf\x3a\xfc\x66\x68\xd5\x83\x64\x97\x4c\xfa\xe0\x83\x00\x0a\x77\xee\xa4\x85\x23\x47\xa7\x0b\x4a\xdd\x81\x63\xbd\x26\x91\xe5\x8e\x9b\xfe\x1f\x5f\x32\xf9\x01\x27\xe0\x16\x39\xe6\x8b\x1c\x93\xc2\xc1\x9d\x74\x0f\x4c\x8b\x1e\xab\x94\x86\x7b\x80\x19\x6b\x67\x2a\x61\xed\x77\xe8\x4c\x3e\xf5\xb0\x4d\xc7\xd0\x3e\x65\xbc\xdf\x9e\x54\xe2\x6b\x6b\x40\x40\xe9\x38\x1f\x26\x68\x7d\xb8\xca\x74\x3a\x56\xb8\x24\xa2\x0f\x51\x1f\x3d\x58\x61\x97\xf8\x7d\x78\xe3\x01\xc5\xcb\xaf\x8d\x2a\x73\xaa\x1f\x0a\xbb\xe4\xcc\x83\x0b\x21\x3f\x58\x7e\xf9\x37\x88\x2c\x77\xbf\x61\xc3\xa9\xb5\x3e\x15\x44\x2e\x0f\x7c\xc0\x32\x12\xd5\xf6\xbf\x75\x2f\x7c\xe4\xad\xd7\x30\xeb\x3b\x3f\xf6\xec\xb2\xe8\x0d\xd0\x87\xb6\x3e\x57\x35\xd6\xb0\xcc\x9f\x96\x76\x6b\xf9\xfc\x3c\xbf\x5a\xc3\xb4\x68\xa1\x4b\x86\xe1\x73\xf5\x7b\x0d\xab\xbe\x14\xa8\x66\x7d\x58\xf6\x61\xda\x07\xd9\x32\x4f\xcd\xbc\xe4\xf1\xc2\x17\x33\x3f\x4d\xac\x20\xbe\xe7\xc5\x6e\xa2\xa6\x10\x44\x53\xf5\x63\x41\x23\x3a\xf5\xf9\x3d\xd5\xe5\x91\x1f\x2e\x8d\xf5\x57\x13\xae\xd4\x80\xea\xae\xb1\x86\x79\xa7\x7a\x79\xd8\x2a\x09\x35\xeb\xff\xcd\xfa\x1b\xb2\xda\x55\x3f\x5f\x6b\xbd\x41\x1a\xea\xea\xe8\xb3\xec\x6f\x64\x34\x9d\xf6\x1b\xc5\x37\xfb\x12\xaa\x4d\xe0\xe6\xc8\xe8\x95\xf9\x0f\xd6\x26\x5c\x6e\x51\x8a\x5b\xb2\x5a\xdd\x9d\x93\xb9\xd6\xb9\x73\xa0\x0d\x6b\xad\x74\xb2\xff\x59\x48\xb8\xb5\x87\x09\xeb\x74\x5c\x1e\xd4\xa3\xf4\x94\x76\xb4\xab\xd5\x0d\x7d\x78\x08\x63\x75\x1d\xd1\xcc\x30\x61\xbf\x43\x12\xda\xed\x57\x06\x64\x52\xb0\xc3\x3f\x03\x11\x4f\xa7\xa1\x2f\xe5\xc3\xc1\xc2\xcb\x6f\x86\xc1\x74\x26\x4a\xf7\xcd\x05\x1b\x3c\xea\x2d\xc5\xe0\x41\x6f\xa9\x22\x41\x6a\xb9\xfb\x58\x2c\x44\xbc\x30\xc0\xd8\x59\x5e\xf6\x92\x38\x0c\xbc\x1e\x9f\x32\x4a\x86\xd0\x53\xff\x5b\x3b\xf7\x1f\x99\x25\xbe\x8e\x2b\xac\x21\x12\x34\x88\xaa\x27\xa0\xb5\x75\x91\x53\x61\x9c\x46\x5e\x6e\xaf\x6e\x78\x0f\x68\x28\x6b\xca\x93\xfa\x6d\x5c\x93\xaf\x8a\x65\x28\xa9\xf2\xb2\x4f\xb8\x09\x2b\xd4\x42\x9b\xca\x41\xb5\xd8\x68\xab\x7b\x5b\xc3\x00\xb3\xc1\x0a\x83\x28\x0c\x22\xbf\x8c\x50\x6c\x7e\x57\x47\x8c\xf8\x86\x3d\x3e\xf2\x57\x35\x2d\xac\xe2\x02\x52\x78\x31\x93\xaa\x73\x0e\x5f\xc3\xe1\x76\x53\x4d\x8d\x8c\xea\x73\x14\xea\xa1\x71\x17\x8c\x87\x18\x08\x9d\xc7\x36\xea\x6c\x8c\xbc\xe9\x7e\x0b\xfb\x52\x60\x75\xaf\x37\xb9\xb6\xde\x48\x09\x20\x05\x69\x5e\xf4\x49\x25\x9d\xc9\x69\x1b\x60\xfe\xe8\xdb\x3b\x79\x3e\x93\x8b\xae\x06\xb9\x4f\xf6\x79\x2b\x68\xb3\xe2\xcc\x00\x8e\xfb\xce\x94\x13\x83\x63\x66\xbc\x93\xce\xd5\xb8\x24\xe7\x7d\x30\x10\xe7\x40\xa5\x12\x8f\x4c\x38\xee\x13\x23\x11\x57\xa1\x9f\xcc\x7c\x5f\x79\x45\xa7\x21\x18\x61\x4c\x3d\x95\xbd\x80\xcc\x31\xe1\x96\x99\x3f\xf1\x39\x8f\xb9\x7e\x74\x15\x10\xe3\x90\x06\xa1\xef\xf5\x44\xdc\x93\xef\xf4\xf6\xcf\xcf\x7b\x13\x1e\x2f\x54\x41\x48\x53\xe7\x3b\x58\x9b\xf0\xad\xf2\x15\x6d\x3b\x44\x22\x87\x5b\x6e\x58\x63\x7d\x27\x7d\x88\xee\x1a\x61\xc0\xee\xb1\x38\x16\x89\xe0\x74\x39\x78\x68\x0d\xad\xe1\x80\x86\xcb\x19\xb5\x1e\x0f\xbc\x20\x11\xf7\xdc\x24\x29\x1b\x58\x8b\x20\xb2\x5c\xa9\xce\x9e\xa2\xc3\x45\xd9\x07\xca\x36\x74\xe5\x27\xf1\xc2\x1f\x3c\xb4\x7e\xb3\x86\xf8\x66\xf5\x76\xf9\xf2\x45\x5f\x09\x5d\x15\x5c\x51\x6a\xe1\x19\xe1\x16\x7b\x0b\xdc\x72\x99\xf9\xac\x4c\xc8\xcf\xf3\x5f\x05\x46\xd1\x8a\xd4\x51\xda\x51\x5b\xea\x24\x17\x1f\xbc\xdf\x27\xfc\xf6\x30\x96\x8b\x5f\x39\xd5\x67\xdc\xa7\xf3\x5e\x54\xa0\xaa\xba\xe6\xeb\x4d\x06\x7c\xd8\x47\x8b\x3a\xad\x1e\xa5\x04\x13\xa2\xd2\xec\xc9\xf9\xe5\x1d\xe5\x1d\xd4\x28\xc1\x7a\xb3\x1f\x4c\x0e\x45\x0a\x7c\x8c\xd6\x70\x5d\xdf\x69\x7d\x88\x61\xb9\x09\xb8\xf2\x8f\x00\x51\x2d\x41\x25\x2c\x4a\x22\xf2\x89\x13\xd3\x34\xd7\xb9\x50\xf6\x99\x93\x1f\xaf\xec\xa2\x55\x51\x95\xb3\x27\x2c\xea\x50\x88\x84\x45\x3d\x6f\x9c\xf9\x91\x38\x09\x12\xe1\x47\xbe\xd4\x88\xe3\x65\xa2\x4c\x75\xc2\x94\x2d\x22\x9a\x05\x53\x2a\x62\x6e\xa5\x89\xcf\x77\xa7\x7e\x24\xac\x20\xf2\xfc\xcb\xb3\x09\x31\xde\xf1\xc0\x43\x17\x95\xdf\x87\x3f\x7f\xb6\x76\x37\xa3\xc9\x2c\x4f\xee\x28\x9a\xc5\x1c\x82\x09\xb9\x23\x77\x4b\xf0\xf0\xa5\x7f\xf5\xf3\x27\xb7\x16\xbe\xa0\xfa\x67\x32\x0b\x26\x02\x7f\xef\xfc\x2e\x05\x3a\xac\x14\xf4\xf3\x67\x64\xa9\x0c\x6c\xf2\x97\x17\xaf\x22\x89\x30\xa6\xf9\x83\x5b\x4b\xee\xcb\xc1\x0f\xd4\x6e\x90\x32\xd2\x60\xc6\xfd\x09\xf8\x8e\x5c\x1d\x48\x9d\x8b\x98\x08\xd3\xa2\xcf\x28\x71\x49\xfa\xf7\xbf\xfb\x16\xf3\x1d\xc7\x49\x2d\xe6\xcb\x0b\xfa\x1e\x2f\xe8\x7b\x7c\x42\x2d\xaa\x9e\x51\x8b\x8e\xb4\xa7\x44\xba\xb6\xb5\xef\x89\x58\xa3\xc1\x7b\x0d\xee\xd4\x6e\x3d\x76\xe1\x96\x3b\x85\x08\x70\x60\x21\xdb\xbd\xb1\xb9\xe5\xbe\x01\xf7\x4c\xfe\x3d\x03\xf7\x48\xfe\x3d\x92\x5d\x9c\xf5\x9d\x2f\x11\xe9\x9b\xb0\xd7\x49\x79\xb4\x9b\xd5\x88\xdb\x58\x13\x00\xd3\xc7\xab\x62\xc0\xef\xfa\xdd\x67\x64\xba\x1c\xd5\x48\xd8\x47\x44\xc0\x91\x7c\x6a\x51\xa4\xa9\x6f\xfb\xce\x75\x9f\xfc\x70\xa7\xf6\xeb\x04\xdc\xc4\xbe\xa2\xe0\x0a\xbb\xa1\x19\x94\x7e\x05\xfd\x51\xee\x9a\x1b\x59\x74\x6d\x2b\x4d\x0a\x72\x7f\xe4\x4b\xf2\xae\x0f\xc6\xdf\xf0\x68\xf9\x0c\xd4\xd5\x48\x5e\xb9\x19\x66\xd8\xd8\xeb\x03\xb7\x18\x85\x23\x89\xfa\xfe\xa8\xac\xd3\x61\x97\xc5\x3b\xb8\x45\xdf\x9b\x98\x25\x75\x82\xfe\xb5\x6b\xb9\x44\x87\x3e\x39\xeb\x9b\x72\xd1\xce\x12\xb9\x84\x2d\x74\x9e\xbd\xb1\xc7\xe4\x8f\x6f\x8a\x65\xe0\x41\x4e\x8d\xc1\xaf\xd7\x6b\xf3\xd9\x59\xe0\xfc\x78\x45\x83\xc8\xfe\x11\x44\x81\xb0\xdf\xf6\xc9\xdc\x35\xc9\xd0\x5c\xaf\x21\xb2\xc6\xe1\x62\x94\xf7\xdb\x8b\x30\xf7\x2f\xa6\x6e\xc2\xa3\xe1\x5e\x10\xf5\x84\x89\x7f\xf8\x08\x93\x10\x1b\x8e\xe3\x8f\xf6\xc9\x63\xd3\x8e\x08\xff\xc3\xff\x0a\xe2\x0f\xff\xab\x69\xcb\x9f\x8e\xfc\x29\xf5\x99\x71\xb8\x80\xb3\xc0\xb4\xf1\x97\x73\x16\xac\x89\x98\x05\x89\xf9\xec\xff\x06\x00\x00\xff\xff\xa5\x26\xd1\x9d\xf3\x81\x01\x00"), + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\xfd\x09\x7b\xdb\xbc\xb2\x20\x0c\xfe\x15\x9b\xad\xab\x03\x44\x65\x46\xf2\x96\x84\x32\x8e\xc6\x49\xec\xec\x76\xe2\xec\xf1\xeb\xce\x07\x52\x90\x4d\x4b\x06\x15\x08\xf4\x12\x8b\xfd\xdb\xe7\x41\x81\xab\x44\x2a\x39\xdd\xb7\x67\xbe\x7b\xdf\x13\x8b\x04\x50\x28\x00\x85\xda\x50\x28\xae\x8f\x62\x19\xe8\x30\x92\x44\xd2\x7b\x27\x9e\x89\xb5\x99\x56\x61\xa0\x9d\x7e\x56\xb0\xa6\x88\x04\x05\x9a\xde\x2b\xa1\x63\x25\xd7\xb4\xcb\x99\x04\xed\x8e\x98\x02\x9d\xe4\xd5\x66\xa4\xa8\xa2\xc8\x26\x68\xc8\x41\xab\xbc\xa0\xdc\x5b\x06\x8e\x28\x90\x34\x49\x68\x01\x4a\x10\x51\x02\xb5\x05\xa2\x00\xa5\x97\x41\xad\x84\x2e\x88\x06\x0b\xbf\xdc\x81\x26\x71\xa9\x83\x6d\x88\x8b\x0e\xc4\x32\xb4\xff\xb4\xcf\x98\x08\xc8\x7b\x2d\x77\x1b\x12\x5e\xea\x76\x07\x78\xd1\x6d\xbc\x0c\xf0\xbf\x01\x13\x4e\x62\x28\xe3\x52\x46\x26\x26\x41\x09\x99\x5d\x08\x0a\x64\xf8\x32\xcc\xff\x3b\xf8\x05\x84\xc3\x02\x86\x65\x14\x39\x09\x4b\x28\x3e\x82\xb0\x40\x31\x58\x06\xfb\xff\x33\xac\x43\x12\xc0\x32\xde\x65\xc4\x03\x12\x95\x10\x7f\x0c\x51\x81\x78\xb8\x0c\xf9\xff\x9f\x63\x89\x48\x08\xb5\xa3\x29\x0f\x27\x22\xa3\xd2\x70\x9e\xc0\xa8\x18\x4e\xb4\x0c\xfc\xff\x65\x23\x1c\x91\x08\x9a\xc6\x58\x1e\xe4\x78\x81\xcd\x6d\x32\xc6\xa4\xcb\x07\xd2\x1d\x11\xf3\xde\x33\xfd\x10\x5d\x6a\x71\x6b\x5b\x40\x81\xe4\x56\xb5\x0d\x88\xbc\x15\x11\xa5\x86\xfb\x59\x43\x28\x86\xbc\xbd\xd8\x14\xe2\x72\x63\x12\x97\xda\xdf\x14\xed\xa1\x98\xc7\x9d\x65\x08\xc0\x17\x60\x10\x5e\x02\x33\x29\x83\x81\x62\x8d\x76\xeb\x00\x41\xb0\x0c\x8a\x04\x25\x68\x7e\x15\x1a\x14\x64\xf0\xa8\x1e\x1e\x84\xb5\x10\x49\x48\x93\x6b\xae\xd6\x46\x4c\x90\x62\x39\xed\xd2\x8c\x22\x45\x4c\x99\x60\xfb\x4a\xf1\x3b\x22\x29\xc4\xac\xdb\x8f\xf7\x64\x3f\xee\x74\xa8\x38\x8d\xcf\x98\x26\xaa\x13\xd3\x7e\xc6\xff\x13\x0a\xd7\x6c\x56\x81\x54\xc0\xd1\x05\x1c\xc1\xba\x7d\xb1\x27\xdb\x6d\xe5\xfa\x7d\xd1\xe9\x50\x7d\x2a\xce\x98\x72\x39\x28\x66\x5e\xe5\xc2\x6f\x22\xe4\xb9\xbe\x60\x02\x8e\x8d\x68\xa1\x09\x85\x21\x23\x8b\x1d\x64\x9b\xe5\x54\x9e\x25\x14\x56\x0d\x24\x03\x08\x71\x8a\x8b\xa0\xc0\x59\xb7\xcf\xf7\x44\x9f\x77\x3a\x34\x3e\xe5\x67\x4c\x9f\xf2\xb3\x0c\x83\xf8\x54\x9e\x31\x05\x71\x42\xa1\x79\x58\x2a\x83\x9a\xcd\x94\xee\xf4\xb2\xb9\xd2\xc5\x5c\xa9\xd3\x38\x87\x2b\x4e\xf5\x19\x93\x20\xfe\x1e\x5f\x03\x4c\x20\x30\xc5\xcc\xee\xd1\xa7\xf1\x19\xa8\x7c\xea\xd5\x5f\x42\xda\xe8\xf5\xbb\x7b\x4c\xf4\xc5\xc6\x46\x0e\x48\x2c\x00\xa2\xd0\x5a\x9e\xe4\x55\xc3\xad\x19\xac\x24\x66\xb8\x15\xca\xf8\x3f\x5e\x18\x64\x1a\x1d\x0e\x66\x81\x72\xc8\x71\x2d\xe4\x9c\x80\x66\x93\x30\x10\x38\x82\xda\x7a\xb6\x77\x55\xf4\x2e\x37\x44\x3f\x43\x66\x2f\x6e\xb7\x49\x9c\xe3\x46\xfb\x19\xbe\x3c\x43\xb2\x13\x53\x08\x58\xb7\x1f\xec\x89\x7e\xd0\xe9\x50\x7e\x1a\x98\x75\x0e\xce\xb0\xaa\x2d\x89\xb3\x92\x8e\x30\xb4\x15\xe4\x34\xc0\x13\x0a\xf7\x2d\xaf\x9b\xd0\x42\xfd\xbb\x2a\x53\xf4\x7d\xcb\xeb\x01\xf7\x24\xf8\x9e\x4a\x70\x9b\x5e\xb0\x19\xb9\x2a\x55\x3f\x30\xac\x37\xc3\x4a\xb1\x16\x68\x26\x53\x6c\xfb\x7a\x63\xa3\x4f\x15\xbb\x22\xf2\x54\x57\x17\x38\x6f\x3e\xad\x36\x3f\x3d\xeb\x4b\xd7\xef\x4b\x26\x5d\x9f\x2a\x77\x1a\xcf\x2e\x88\x74\x79\xa9\xa5\xa9\x77\xbe\x92\x55\x9c\x9e\xf5\x95\xeb\xb7\xdb\xda\xec\x62\xb3\x97\x41\x33\xed\xfa\x54\x58\x70\xb8\x84\x2e\x07\xed\x72\x9a\xc3\x3d\x30\xfc\x9a\xc2\x1d\x23\x7a\x01\xb2\xe1\xf6\x19\xec\xb8\x0c\xbb\xdd\x16\xd5\x0e\x40\x30\xe1\xfa\x34\xb6\xdd\xdc\x16\xdd\x80\xa8\x76\x15\x9b\xae\xc2\xa5\x7e\x8c\x70\x28\x96\x77\xb1\xa7\x76\x3b\xae\xeb\x0e\x62\x16\xbb\x3e\xe5\xb6\xd3\xfd\x6a\xa7\x10\x57\x3b\xe6\xa6\xe3\xb8\xa6\x63\x23\x55\xb2\xae\x83\xfa\xae\xdb\x6d\xde\xdc\x3f\x70\xc6\x5d\x9f\x06\x16\x8b\x9b\x65\x2c\x80\x57\x31\x09\x68\x95\x9d\x69\x28\x04\xf8\x01\x31\x44\xe1\xce\x22\xa5\xeb\xb9\xec\x2b\xa2\x0d\x07\xd7\x44\x51\x9a\xe0\x7f\xfd\x12\x28\xf1\x57\xa0\x2c\x1f\x19\x9b\xda\x25\xc2\xd4\x8c\xb1\x1b\x3d\xe8\x7a\xe6\xc7\x9d\x1e\x6c\xf4\xbc\x1e\xf6\xb0\xc4\x7a\x4b\x3c\xaf\xa1\x28\x88\xe4\x2c\x9a\x08\x77\x12\x9d\x13\xd9\x71\xbc\xb5\xbd\x50\x6a\xa1\x24\x9f\xcc\xfe\xed\x50\x50\xe5\x3d\xf7\xcc\xec\x02\x7d\xa1\xa2\x9b\xb5\x03\xa5\x22\x45\x9c\x0b\xad\xa7\x33\xef\xe1\xc3\xf3\x50\x5f\xc4\xbe\x1b\x44\x57\x0f\xc5\xe4\xea\x61\x10\x29\xf1\xd0\x9f\x44\xfe\xc3\x9e\xdb\x75\xbb\x0f\x2f\x42\xa9\x67\x0f\x9d\x8e\xec\x38\xee\xd5\xd0\x29\x89\xe7\xc3\x05\x9e\x09\x66\x63\x40\xcc\x8e\x70\xd5\xbb\x20\x68\xdf\xf0\x16\xcd\x84\x3b\x8d\xa6\x84\xd2\xbe\x29\xd3\xb8\x6c\x3e\x96\x97\xf8\x5b\x0e\xf5\xa8\xd8\x14\xe1\x88\xf4\xba\xdd\x3d\x4d\x33\xfe\x6a\x17\xff\x18\xfb\xa5\xb0\xde\xed\x87\x23\x22\x19\x63\x2a\xad\x61\xdf\x38\x91\x7f\x29\x02\xed\xac\x33\x7d\x37\x15\xd1\x68\x4d\xce\xe7\x32\x9e\x4c\x8c\xce\x90\xff\xca\x9a\x38\x59\xc7\x0e\xcb\xab\xb7\xdb\xcf\xc8\x0e\x85\xf5\x5e\xce\x0b\xe3\xb5\x50\xae\x49\xb7\xb5\xd7\x6d\xb7\x89\x64\x07\x48\x1d\xca\xfc\x35\x88\x48\x1a\x8e\xc8\xfa\x11\x91\x28\xad\xcc\x3f\xba\xd3\x33\xc3\x4b\xb1\xea\xf5\x33\xf4\x90\xb7\x5c\xb2\x19\x39\xa4\xf0\x71\x49\x87\x48\x6b\x1d\xa6\x9c\xbc\x58\xbc\x57\x19\x0b\xaa\x1d\x5d\x36\x3d\x38\x13\x83\xae\x27\xf7\x14\x92\x95\x99\x8b\x75\xe9\xb6\xd2\x72\xa2\xd9\x2b\xc3\xe9\xcc\xc6\xa1\x74\xa0\xbd\xf4\x85\x0f\xca\xf5\xf1\x85\x79\x0a\x40\xb9\x81\x15\x02\x86\x4f\xa2\xf2\xd2\x6e\xaf\x57\x1b\x5b\xee\x69\xd5\x98\x82\xb2\xe7\x73\x03\x6d\xd0\xf3\x94\xeb\x1b\x04\xba\x56\xeb\x7a\xdb\x30\x4e\x3b\x2a\xba\xd7\x4d\x28\xfc\x6c\xd4\x77\xd2\x4a\xbd\xe6\x5d\xd0\xdd\x7b\x95\x89\xbe\xc6\x1a\xac\xb1\x8a\xdd\xa5\xb6\x38\x1f\xc9\x5e\x77\x70\xa7\x3d\x3d\xb8\xd5\xde\x8d\x36\xaa\xc2\x6f\xd6\x2d\x56\xe3\xb8\x22\xbe\x72\xd1\x95\x97\x3f\xad\xca\xe7\xac\x06\x04\x9e\x2e\xd5\xfa\x54\x32\x28\x64\xf1\xfa\xa4\x8c\xd6\x7d\x92\x53\xa0\x40\x0a\xb4\x2a\xa4\x3c\x15\x67\xd5\x02\x95\xea\x96\xa6\x20\x1b\x04\x4e\xfe\x73\x36\x23\x2f\x4b\x94\xf4\xd2\x82\x37\x74\x34\xd3\x2a\x94\xe7\x25\xb2\xcf\xe9\xa8\xa3\x52\xd2\xf1\xb3\x57\xaa\x6f\x11\xba\xb2\x34\x90\x12\x40\xbf\xa4\xda\x94\x84\x2a\x72\xed\xa2\x6a\x05\x9f\x5f\x4d\xc4\x20\x3b\x86\x5d\xfd\x47\x85\x7f\xa7\xac\xd9\xb9\xe4\x4c\xb9\xc1\x05\x57\xcf\xa2\xa1\xd8\xd7\x24\xa6\x7d\xbe\xb7\xb3\xb3\xf9\x64\x77\x3e\xdf\xd9\xdd\xea\x3d\xd9\xe3\x03\x92\xaa\x74\x9f\xac\x52\x47\xc1\xa8\x79\x5e\xf5\x6d\x47\x9d\xc6\x9d\x9e\x2d\x64\x9b\x34\xc9\x19\xd3\x65\x14\x4a\xe2\x38\x75\x14\x56\xa0\x79\x7a\x06\x15\x35\xcc\x6a\xbb\x39\x82\x86\x71\x04\x4b\x78\xc6\x9d\x0e\x04\x55\x5c\x83\xf9\x9c\xf0\x8e\x6d\x60\x90\x04\x83\x1e\xa7\xd4\xc8\x53\xe4\x90\x3c\xc7\x4c\x97\x30\xeb\xff\x47\x4a\x78\x86\x96\xb6\x68\xe9\xbf\x46\x4b\xe7\x68\x59\xd5\xdb\xa0\x66\xf6\x5e\x21\xcf\x90\x98\xde\xaf\xd4\xb0\x32\x74\x8c\x0a\x9f\xa2\x12\x33\x54\xe2\x79\x15\x15\x81\x2b\xb9\xbb\xb5\xd9\x9d\xcf\x77\x1e\x6d\x6d\x6f\xed\xf1\xf9\xdc\xe8\xb3\xa7\x1b\x1b\xe2\xcc\xa8\xae\x19\x16\xf1\x02\x16\xf0\xa5\x89\x16\x95\x3b\x9b\x4e\x42\xc3\xe3\x13\x0a\xaf\x9b\x6b\xe1\xd4\x62\xa5\x77\x35\x83\xa9\xd5\xce\xff\x82\x88\xad\x4e\x9b\x29\xed\x46\xad\x8d\xab\x44\xa1\xa9\xd9\x9e\x71\x75\xd4\xf1\x7c\x4e\x4c\xf5\x8d\x0d\x7d\xd6\x11\x96\x24\x04\xcd\x45\x50\x37\xc9\x64\x51\x3a\xfd\x2f\x56\x58\xb0\xff\xbd\x98\xac\x2f\xa0\xd2\x4b\x72\x9c\x28\x7c\x6e\x98\xdd\x8d\xde\x9e\x72\x43\x39\x14\xb7\xc7\x23\x3b\xc5\xdf\x9b\xd6\xa1\xcb\xd8\x42\xd5\x0f\x8d\x4c\x26\xb3\x79\xf2\x21\x1a\xf9\x36\xe1\x33\xfd\x2a\x6f\xcf\xf2\xb2\x8d\xac\x7a\x42\xe1\xeb\x12\x48\x3b\x55\xb9\x21\x12\x8e\x88\xde\xeb\x65\xfc\xb2\x55\x62\x8d\x5d\x40\xa5\x7e\xa3\xb7\x67\xa6\xa5\xc0\x14\xf5\x9f\x4c\x97\x17\x14\x44\x87\xe9\xaa\x06\x8f\x0b\xf5\x6d\x25\xc7\x84\x1f\x8d\x92\x53\x6e\xac\x50\x1d\xe5\x03\x34\x81\xdf\x34\xb7\x7e\xb8\xaa\xf5\x43\x35\xef\x62\xf1\x3b\xae\x2f\xdc\x69\x74\xd3\xac\xbe\xfe\x97\x6c\x94\xba\xea\xbf\x64\xbf\x58\x44\x26\x07\xcf\x48\xaf\x47\xbd\xee\x9e\x6e\xb7\xe5\x5e\x77\x3e\xd7\x46\xdf\xea\xee\xc9\x81\xee\x48\x4f\x5b\x2d\x1c\x7b\xe4\x9a\xcb\x4d\x3b\x3f\x52\x32\x7c\x15\x88\x70\x02\x2a\x7d\x18\x4d\xa2\x48\x81\x4e\x9f\x54\x14\xcb\x21\x88\xf4\x69\x12\x9d\x37\xca\x99\x76\x7b\xd5\xa8\xe7\xf3\x55\xa5\xeb\x8c\x65\xbc\x2d\x96\xec\x4f\xc6\x57\x46\x38\x86\xe3\x77\xf8\x1e\x8b\xb3\xe7\xd0\xd8\xd3\xed\x76\xb8\xc7\xd3\xad\x17\xb1\xb8\xbc\xe7\x14\xed\x07\x4c\x9e\x86\x9d\xce\x19\x63\x2c\x3e\x55\x9d\xce\x59\xbb\x4d\x7a\x66\x06\xa3\x01\xd1\x9d\x0e\x08\xd6\x33\x82\xab\xd3\x01\xe4\xcf\x8c\x91\xdd\xad\xed\xc7\x8f\xdb\x11\x1d\x2c\x34\xf4\x7a\x34\x67\x89\x4f\x49\x30\x50\xde\x46\x0f\x75\xef\x84\x02\x97\xcd\x4c\x4d\xed\x65\x0c\x7a\x50\xed\x42\x57\x51\xa5\x03\xb3\xf9\xb5\x3b\x8b\xfd\x99\x56\x44\xc1\x26\xa5\x74\xa0\x3a\x9b\xde\x46\xcf\xc3\xa2\x53\x75\x46\xe9\xc0\xf9\xc7\xe8\xdf\xcc\x3c\x0d\x36\x36\x3d\xd5\xe9\x99\x0a\x1b\x46\xeb\x0b\x56\xa0\xb1\xd0\x9b\xa1\xa1\x84\x42\x24\x6b\x79\x5b\x5f\xee\xe5\x8c\x4d\x76\x3a\x39\x11\x96\x61\x48\x6a\x37\xf2\xf6\x63\xc3\xcd\x0a\xcb\x43\x26\xf9\x0f\x0a\xa3\x3a\x8c\x4a\xfb\xbd\x5f\xcc\x4e\x5f\x65\x1d\xc5\x6c\x01\xd9\x8d\xed\xc7\x96\x79\x76\xe7\x73\xb9\xc7\x62\xea\x2b\xc1\xc7\x7d\xc1\xe4\x03\xd1\x89\xb3\xfe\x8e\x89\xb2\xab\xe1\xd7\x0f\xca\x8e\xa1\x5b\x3b\x36\x51\x37\xb6\xed\xc7\xff\x16\xf3\xb9\xf8\xf7\xce\x23\x63\xb4\xec\xee\xd8\xa7\x47\x5d\xd4\x09\xc5\xde\x93\x47\xf3\x79\xaf\xbb\xb9\x27\x52\x74\x34\xeb\xed\x3e\xd0\x1d\xb1\xf1\xf8\x51\x22\x26\x33\xb1\x96\xbf\xd8\xd9\xe9\x57\x5f\x6c\x3f\x2e\x90\x96\xa0\x51\x15\x92\x8c\xfc\x69\x23\xc4\x25\x8e\xa8\x28\x04\x8c\xef\x75\x07\xd9\x6e\xf0\x78\x27\xe7\xb0\x6a\x2f\x48\x77\x44\xb8\xb0\x23\x3a\x1d\xda\x47\xfa\x0f\x07\x44\xb0\x1e\x68\xab\xb8\x2d\xd1\x7f\x48\xdb\x6d\x53\xb9\xa0\x78\x9e\x11\x7b\x3d\x83\x72\xce\x9d\xbe\x74\xf9\x96\xb1\x62\x3b\xcc\xb9\x72\x28\x48\x97\xdf\xa4\x8f\xa1\x43\xfb\x5a\xdd\x65\xc4\x78\xa4\xc9\x89\x38\x3f\xb8\x9d\xa2\x6f\x9f\x26\x01\xd7\xc1\x45\x49\xc9\xbf\xd4\x89\x61\xb9\x13\xd9\xcc\x73\xe3\xc9\xc4\x70\x11\xf7\x2a\x6d\xba\xda\x9f\x88\x72\x05\x38\xeb\x1a\xf5\x0c\x42\x56\x92\x64\x10\xb1\x8d\x5e\x9f\x77\x3a\x7b\xb2\xdd\x46\xb1\x23\x6e\x45\x40\x02\xa3\x23\x46\xeb\xe5\x9a\xfd\x02\xe0\x88\x89\xdc\x7f\x0a\x7e\xaa\x49\x8f\x68\xbf\xbb\x37\x4a\x27\x7e\xc6\xc4\xe9\xe8\xac\xef\x9f\x6e\x6c\x8c\xce\xd8\x6c\x70\xa4\xc9\x8c\x7a\x97\x3a\x89\x33\xe7\xd0\xf7\x18\xc4\x69\xf7\x0c\x84\x5d\x55\xe0\x70\x40\x7c\x4a\x29\x44\xe5\x4e\x73\x2d\xac\x78\xc5\x42\x48\xdd\x56\x25\x3f\x4a\x0c\x12\x78\xb6\x1c\x81\xd9\x59\x59\x3b\x25\xa6\x13\x8e\x5a\x55\xf9\x7c\x26\x1c\x91\xa0\xd3\xf9\x37\x8b\xf3\x7d\xdb\x2f\x1c\x7f\x5c\x9d\xc7\x57\x42\xea\x59\x36\xc8\x2d\xc8\x9c\xf5\xca\x0c\x52\xe5\xaa\x4e\x5e\xf3\x54\x9d\xf5\x8d\x22\xa9\xce\x98\x30\x83\x15\x38\xd8\xcc\xb3\x69\x87\x2b\xa1\xa8\xbe\xd4\xc5\xe6\x19\x04\x70\x40\x34\xa5\x34\xa1\x66\xf5\xaf\x57\xf3\x0e\x9d\xad\x69\x79\x2d\x83\xca\x7a\xc9\x5c\x27\x0b\xb3\x65\x15\xb8\xb3\xd7\xc3\x74\xcf\x66\x2a\x45\xaa\x78\x72\x08\xed\x62\x50\x5a\x05\x9c\x0d\x64\xb1\x3e\xa5\x50\x5e\x98\x00\x4a\xda\xc8\x70\x99\x0d\x15\x6e\xdc\x2e\x0c\x33\x63\xb8\xc9\x94\x33\xd5\x7a\x20\x8a\x6a\xb9\x65\xda\x5a\xaa\xb7\x05\x23\x4f\xc2\x79\xe6\x16\xbe\x5a\xd5\xf5\x36\x5a\xd8\x17\x9e\x4c\x52\x44\x2f\x9a\x6a\xdb\x8e\x8c\xd8\x49\x28\x4c\x57\x08\x97\xb4\x1e\x68\xac\x79\x2e\xeb\x1d\xb7\x8b\x95\x41\x9c\x35\xfb\x5e\x97\x2b\x43\x7c\xb6\xca\x63\x5a\xd7\x00\x38\x36\xe1\xb5\x4d\x4a\x67\x6e\x0b\x8d\x20\xc0\x66\x41\x43\xb3\xd2\xe1\xda\x52\x43\x08\xb1\x69\xd4\xd8\x14\xa2\x55\x8d\x21\x3a\xab\x63\xb1\x25\xd6\x79\x67\x5e\xbd\xfe\x78\x7c\xe4\x4e\xb9\x9a\x09\xf4\xba\x2e\xb2\xcf\x8f\x31\x19\x93\xcf\x1c\x9c\x4f\x17\xe1\x6c\x2d\x9c\xad\xc9\x48\xaf\x5d\xf3\x49\x38\x5c\x33\x2d\xd7\xd7\x9c\x8e\x74\xaf\xc4\x6c\xc6\xcf\x05\x1c\x49\x03\x83\x22\xc3\xbd\x69\xa4\x04\xec\xf6\x52\x5a\x27\x6f\x41\x89\x77\x69\xad\xd9\x4d\x88\x28\xb8\x2d\x7a\x1f\xf0\x99\x58\xdb\xf2\x52\x9f\xa1\x1f\x45\x13\xc1\x4b\x2e\x43\x35\x78\x15\x13\x45\xbd\x7d\x49\x1c\xbe\xf6\xf4\xf8\xf8\xad\x03\x46\x51\x33\xad\x36\xb3\x56\x32\xbe\xf2\x85\x2a\x1c\x77\x6a\x80\xd5\xe5\xda\xab\xa3\x4f\xa6\xba\xb7\xb1\xd9\xdb\x7e\xb4\xfd\x78\x6b\x77\xfb\xd1\x9e\x6a\xb7\xd5\x5e\xf1\xdc\x6e\x93\xee\x1c\x35\x9c\xac\xab\xf5\x70\x76\x18\xca\x50\x9b\xd9\x9a\xcf\xd5\x7f\xf5\x16\xa1\x61\x35\x8b\xc2\xf6\x02\x0a\x0d\x78\x1f\xbe\x3d\xde\xff\x54\x20\xbe\x9b\xb5\x5a\xf4\x14\x65\xad\xd4\x5a\x28\x67\x9a\xcb\xc0\xbc\xfc\x88\x95\xb0\xa4\xe3\x38\x19\xc8\x8f\x9f\x4e\x5e\x1d\xbd\x28\x60\x3e\xf1\x4a\xb2\x2e\x1b\x8d\x74\x03\x5b\xdf\xbc\x2c\xea\xee\x64\x75\x5f\xc5\xc4\x2e\xa8\x7d\xff\x28\x7b\x8f\xcc\xdb\x0d\x67\x19\x13\x1f\x8c\xa5\xf5\x67\xc2\x41\xd6\xff\xdb\x57\x1f\x4b\x23\x7a\xfc\xe7\x96\xb7\x32\x6d\x2a\xd7\xf6\x4f\x4e\xf6\xbf\x17\x8d\x7b\x5d\x2f\xb3\xf9\x86\xb5\x6e\x66\x55\x38\x97\xe7\xf3\x75\xa2\xad\x63\x2e\x13\x45\x29\xd0\xe3\xa7\xaf\x0f\x9e\x7d\x5a\xbb\x09\xf5\xc5\x1a\x5f\x1b\x85\x62\x32\x5c\x93\xfc\x4a\x0c\xd7\xfe\x1f\xa7\xa3\x3b\xce\xff\x83\x1d\x5a\x69\x70\x97\x22\x75\xaa\x8b\x93\xc0\x17\x9c\x08\x3a\x10\x1e\x6e\x87\xef\xa8\xbf\xa0\x47\xd6\xa2\xd8\xf3\xac\xae\x29\x5d\x81\x22\x61\x71\x9c\x0b\xc8\x14\x23\x0c\x47\x44\xe5\xc6\x71\x5c\xa9\xb6\xf6\xf6\xf8\xe8\xc5\xc1\xc9\x1a\x47\x58\x6b\x47\x42\x0c\xd7\x50\x9e\xac\x39\x9d\xb8\xe3\xac\xf9\xb1\x5e\x8b\xe4\xe4\x6e\x6d\x26\xc4\x9a\xd3\xc9\xc0\x74\x9c\x35\x21\xb5\x0a\xc5\x0c\x3b\x28\x8d\x26\x6e\x18\xcd\x07\x8c\xa7\x28\x8d\x66\xd3\xfb\xe3\x34\xff\x61\x80\x76\xb6\xf3\x29\xe5\xac\x30\xcc\x03\xbb\x3c\x38\xf0\x0b\x3e\x3b\xbe\x91\xef\x55\x34\x15\x4a\xdf\x19\x35\xe9\xbe\x84\x6f\x70\x66\xe5\x2b\x22\x4b\xcb\xec\xe8\xbb\xe1\x6f\x16\x63\xce\xae\xc8\x31\xb1\x4f\x50\xf8\xdf\x5e\xc5\xe4\x8b\x26\xc5\x90\xb6\xbc\xac\xff\x90\x49\x77\x04\x11\x93\xee\x39\x8c\x58\xb7\x3f\xda\x8b\x32\x4d\x77\x64\x34\x78\x44\x20\x3a\x1d\x9d\xa5\xcb\x53\xed\x5e\xf4\x43\x16\x12\xd3\x59\xa9\xa7\x30\xeb\x65\xdb\x2b\xd0\x5f\x98\x6b\x7c\x7d\x81\x2d\x0d\x93\x10\x69\x8b\x9d\x1c\x2f\x9f\xb5\x60\x66\xb0\xea\xcf\x5c\xbf\x3f\x63\x33\xd7\x4f\x91\x99\x59\x7f\x6e\x38\x22\x0b\xa8\xf8\xec\xca\x00\x04\x3f\x47\xe6\x63\x4c\xbe\x72\x33\x72\xa3\xfb\xa5\x5d\x78\x0b\x8c\x5c\xba\x3c\xe3\xd3\xb6\x46\xb7\xb4\xdf\xa5\x19\x59\x29\x92\xa6\x46\x57\x52\x7f\x38\x4d\x4f\x95\x46\xcb\xcd\xf1\x30\x3d\x9d\xc5\xa0\xba\x88\x1f\xb8\x11\x53\xb8\x88\x78\x00\x1f\xb8\xbc\x34\xa7\x9a\xc4\xb4\x1c\xa0\x53\x0e\x0d\x1a\x93\x77\x1c\x72\x34\x6a\x02\x85\x6c\xb0\x46\x29\x4a\xa7\x2a\x7f\x72\x91\x76\x70\x3b\x15\x81\x0e\xe5\xb9\x11\x62\xb9\xf0\x2a\x0e\xc0\x65\xee\xb5\x5f\x3e\xed\x92\x6e\x0b\x6d\x86\x56\x71\xda\xb4\x24\xb8\xba\x5e\x75\x09\xa4\xcb\x0d\x1c\x97\xf7\x53\xb9\x96\x0a\xaa\x54\x58\xa4\xdc\xbf\xc2\x84\xd7\xbb\x8b\x0c\xdc\x0d\x10\x46\x90\x31\xe5\x94\xc3\x66\x5b\x37\xf3\x64\xc9\xfc\x88\x29\x67\xa3\x39\x84\x21\x42\x18\xb6\xdb\xcb\xb5\x4a\xb8\x0a\xac\x25\xea\x6a\x6d\x15\xb5\x46\x58\x6b\xd4\x6e\x3f\x33\xb5\xce\x41\xb9\xe7\xc5\x76\xc8\x6b\x5d\x60\xad\x8b\x3a\x58\xb9\xb8\x29\x01\x28\x91\xe0\xb3\x66\xbf\xdf\x7a\xe1\x33\x2c\x16\xa1\xec\x10\x10\x7b\x1a\x03\x80\x0c\x01\x9a\x8e\x31\x18\xe5\x54\x9c\x35\x9d\x10\x1e\x36\xaa\x2c\xa8\x24\x59\x79\x1c\x8e\xee\x08\x2a\x2f\x60\xd8\x21\x48\xda\x71\x9c\xb2\x1a\x73\x24\xeb\x4f\x98\x2e\xab\xef\x4d\x7f\x1f\x57\xf9\x58\x4e\xe5\x19\xb3\xfd\xe8\x54\xb7\x7e\x25\x99\x01\x1e\x4f\x26\xa5\xee\xde\x96\xc0\xde\xb7\xbc\x2e\x70\xa3\x8c\xe7\xc5\x3f\xab\xc5\xbd\x85\xe2\xdf\xd5\xe2\x4d\xf0\x3d\x09\x81\x67\xfa\xb0\xda\xff\xf1\x0a\xed\x7f\x0b\x6b\x0f\xd1\xa0\x80\xa7\x2b\x2a\x6e\x97\x2a\xe2\x48\x3e\xc9\xf2\xc1\xde\x09\x22\x61\xad\x45\x1c\x82\xf0\x3e\xc9\x4e\x27\x35\x43\x70\x96\x2f\xbc\xd3\xb3\x24\xe3\xa8\xaf\x71\x56\x4a\xa1\x26\xcf\xcb\xdc\xe1\xb7\x24\x65\x96\x20\xc9\x5b\x49\x4e\xd2\xad\x5d\xda\xdc\x2f\x53\x24\xa5\x7b\x61\xed\x30\x45\xe1\x35\x1e\x2b\xe0\x79\x59\x65\x34\xe5\x75\x59\x00\xff\xd2\x96\x02\x76\xf3\xdb\x9a\x9b\xf6\x9c\x45\xb2\xf5\x1e\x7c\x91\xec\xf4\xac\x18\xe9\xeb\xcc\x5c\xfe\x22\xd3\x08\x18\x0a\xeb\xef\xd3\x38\x19\xd3\xa2\xdb\x97\xec\x8b\x74\x67\x17\xe1\x48\x13\xda\xa7\xef\x4c\x83\x3e\xc2\x2a\xad\xda\x3b\x1c\x2f\x3a\xd7\x94\x9b\x39\x09\xa4\xd9\x86\x6e\xcb\xec\x8c\xae\x3d\x72\xef\x99\x3f\x79\xbd\xf3\x76\x5b\xb9\xe7\xc8\xb5\x64\x9f\x2a\xf7\x9c\x99\xc7\x10\xb9\xb3\xd9\x73\x76\x7c\x06\x20\x16\xf8\xc4\x80\x33\xd2\x2a\xab\x89\x8e\x28\x83\x3c\xc6\x53\x66\xbc\xfc\x3a\x0a\x87\x58\x35\xc0\xfe\xfd\xca\xec\x18\x60\x12\x70\xbd\x12\x8a\x82\x60\xc7\xe2\x94\x22\xa9\xdc\x8b\xea\x06\x4e\xbb\x1f\x61\xf7\x17\xd9\x3c\x50\xeb\x03\x33\x98\x18\xb2\x43\x9f\x75\xd7\xeb\x19\xdb\xd3\x54\x85\xd0\x53\xee\x79\x02\x59\xdb\x61\x62\x69\xf7\x45\x65\x11\xcb\x96\x60\x79\x11\x55\x36\x7d\x52\xdc\xac\x7d\x7b\xf7\xf6\xa5\xd6\xd3\x13\xf1\x2b\x16\x33\xdd\x5f\xaf\x12\xb4\x99\xaa\x20\x2c\xd4\x9d\xbe\x74\xf9\x70\x78\x70\x2d\xa4\x7e\x1b\xce\xb4\x90\x42\x11\x67\xaa\xa2\x73\x25\x66\x33\xa7\x22\x99\x32\xc6\xf5\x2c\xba\x9a\xc6\x9a\xfb\x13\xd1\x6e\x1b\xaa\x74\x39\xb9\xf7\x3f\x7a\xd2\x9d\x44\x7c\x28\x86\xe0\x7f\xf2\xa4\xab\x23\xcd\x27\x18\x9d\x92\x10\x09\x31\x7a\xbf\x96\xfa\x11\x4a\x45\xaa\xd4\x09\xbd\x57\xe4\xa7\x24\xb3\x10\xa3\x5a\xea\x5a\xe8\xf0\x4a\x44\xb1\x5e\x6e\x33\x69\x6e\x63\xd0\x5a\x68\x50\xe7\xb1\x23\x82\x49\xb8\x0f\xde\x7b\xc2\x55\x62\x36\x8d\xe4\x4c\x7c\x3e\x79\x0b\xfe\x9d\x77\xef\x7f\xf5\x84\x3b\xd3\x5c\xc7\x33\x08\xa2\xfc\xf7\x27\x71\xab\x13\x08\x02\xaf\x3c\x4b\x96\x07\x84\xb1\x3d\x07\x2f\x4e\xc1\x0b\x97\xab\x4c\xcf\x08\x9d\x7f\xd4\x3f\xd2\xa1\xb0\xfa\xc8\xb2\x70\x72\x3a\xde\x9a\x83\x04\xd8\xdd\xe3\x99\x8a\x12\xa7\xfe\xf1\x50\x9e\x93\x2e\x70\x0a\x61\xe5\x15\xef\x6c\xd2\xbe\x62\xb7\x64\xc2\xcb\x21\xf5\x05\x13\x3f\xd2\x24\x08\x89\xa4\x83\xb0\xe3\x00\xda\xc1\xdc\x0b\x69\x02\x8a\x26\xc5\x79\x27\x11\xee\xb9\xd0\xfb\x93\xc9\x49\x3a\x2f\x2f\x05\x1f\x0a\x35\x23\x94\x82\xff\xa1\x34\x5f\x29\xdf\x10\x56\xb9\xb0\x93\xb4\xb7\xd9\xed\xce\xe7\x5b\xdd\xee\x1e\xcb\x5e\xd1\xdc\x07\xef\x47\xc3\x3b\x26\xf3\xf6\x66\x42\xe1\xa7\x24\xa3\x90\x68\x9a\x9e\x87\x30\x45\x74\x59\x11\x8d\xe9\xe0\xad\x24\xb1\xcb\xa9\x47\x1a\x01\x8c\x49\x14\x62\x64\x17\xba\xcf\x88\x04\xe1\xfa\xdb\x46\x4f\x4b\xac\xdf\x55\xba\xd1\x54\x48\x22\xdc\x60\x0a\xc2\x0d\xde\xc3\x7a\x77\xd9\x6d\x80\x74\xe5\x1b\x55\x39\x78\x6f\xc0\xac\x37\x1f\x7a\x06\x41\x5f\xbb\x7e\xdf\x86\xf2\x49\x77\x26\x74\xba\xfd\xec\x4c\x11\xed\x72\x1b\x72\x66\x74\x86\x12\xba\x77\x53\xa3\x8c\xfa\xdb\xae\x0f\xd2\x35\x86\xdd\x33\x25\x86\x42\xea\x90\x4f\x66\x06\xec\x09\x98\xbd\xea\x06\x6f\x68\xbb\x4d\xa4\x9b\x52\xbf\x29\x79\x63\xb4\x5c\x3c\x09\x4c\xe3\x2b\x84\xeb\x7f\xe8\xe7\xca\xca\x4c\xc8\x21\xb9\x36\xd3\x38\x20\x35\xf8\x38\xcf\x22\xa9\x85\xd4\x1b\x06\x03\x07\xa3\x0d\xc1\xa0\xee\xe1\xaf\xd2\x56\x91\x2e\xf7\x23\xa5\x09\x5e\x89\xa9\x78\xe6\x4a\x2e\x2c\x14\x78\xbe\x27\x5c\x1f\x78\xcd\x5e\x10\x2e\x37\x12\x20\xd7\x7c\xc3\x10\x30\x56\xd9\x48\xd2\x15\x7e\xb1\xcf\x46\x2c\x09\x90\x6e\x70\x6e\xfe\x39\x36\xff\xbc\xac\x6c\x63\x5b\xaf\xf4\xc6\x22\x99\xcb\x98\xcf\x0b\x2e\x31\xbb\x65\xc6\xe4\x46\x82\x55\x95\x07\xca\x1d\x4d\xf8\xf9\xcc\x33\x12\x60\xad\x4b\x69\x1f\x75\xfc\xf9\xfc\x19\x49\x8f\x08\x43\x76\x9f\x40\xc4\x48\xc0\x34\x41\x45\xdf\xe5\x30\x62\x9c\xcc\x20\xa2\xe0\xb3\x1a\x3e\x52\x8d\xae\xf9\x2e\xb3\xed\xfc\x1d\x43\x6f\x62\x97\xb7\xdb\x84\x68\xa6\xe7\xf3\xfb\x84\x9e\x8a\x33\x16\xbb\x9c\x08\x8c\x4a\x33\x35\xd8\x07\x49\xe2\x52\xb4\x81\x4e\x48\x08\xb3\xd2\xa0\x66\xb6\xaf\x20\x0d\x0f\x8c\x28\x8c\x48\x64\x2c\x0f\x30\xea\x9c\x22\x21\x04\xae\x0f\x31\x89\x8a\xe3\xb9\xea\x5b\xf0\x07\xf7\xd3\x48\xe9\x99\xe7\x27\xde\xbd\x15\x33\xdf\x25\x06\x0c\x65\x7d\x7c\x28\x0d\x48\xb0\xfb\x73\xf4\x8f\xda\x39\x4a\x20\x66\xd2\x0d\x80\x33\xe9\x0e\x21\x60\xd2\x15\x80\xf6\x68\x1e\xc9\xec\x5e\xb0\x13\xb3\x03\x8f\x0b\x07\xfb\x5a\xf9\xa2\x04\x96\x48\xb8\x6f\x79\x3b\xe0\xd7\x90\x8b\x74\x79\xe5\x68\xd7\x6d\x0d\x6e\x09\x07\x81\xaa\xa5\x17\xb4\xdb\xe1\x60\x1f\x6f\x12\x29\x37\x04\xe5\x5e\x9a\xb7\xb7\xf8\x22\x18\x28\xd7\xc8\x51\xf3\xca\x90\x02\x48\xd7\xa7\x56\x19\xfa\xfa\xb7\xca\x90\x72\xcf\xc9\xa2\x2e\xd4\xa0\x50\x8f\xc9\x2f\x09\xd2\xbd\x80\x54\x67\x55\x55\xea\xfb\xb6\xfa\x2a\x08\x6a\xb2\x63\x4f\xc1\xc4\x68\xb3\x85\x62\xf4\x63\x51\x9d\xbd\x32\xe5\x66\x0c\x6f\x56\xea\xb1\xd2\x93\x10\x2d\x38\xc6\xa5\xaa\xc6\x71\x97\x82\xc2\x30\x2c\x51\x29\xb2\xde\x05\xdc\x65\x46\x23\x07\xf3\x8c\x87\xb8\xe9\xb3\xa4\x46\xc5\x3c\x8d\xcf\xcc\x10\x9d\xd1\xad\x03\xdc\x13\xa7\xf1\xd9\x7c\x7e\x1f\x7a\x2d\xb8\xf4\x5a\x95\x4b\x2b\x4a\x15\x9b\x38\x35\x24\x55\x6e\x48\x66\xfe\x25\xe5\x8e\x81\x33\x32\x62\x31\xf8\x4c\xc0\x98\xc8\xc1\x77\x79\x3a\x3a\x73\x85\x67\xff\x8e\x2a\x72\xaa\x38\x84\xf1\xfb\x0a\x23\x7c\x7f\x51\xa3\x26\x4e\x4b\x2c\x45\x1a\xbd\x69\x52\x84\x84\xa2\x3e\xa7\x4f\xe3\x33\x46\x42\xc6\xcd\xf6\x8d\x30\xb4\x88\x96\xf0\x06\x39\x88\xdc\x90\x5d\x91\x10\x22\x37\xa4\x5e\xe4\x5e\xa6\x0f\x97\x14\x22\x9a\x3b\x60\x8b\xc0\x63\xe5\x5e\xf5\x03\xd7\xef\x07\x2c\x70\x7d\x8a\x63\x35\xbb\xce\x8c\x36\xed\xb8\x5f\x71\xf5\x22\x1a\xe9\x9c\xb8\x11\x68\xb8\x9f\x7a\xca\x95\xf0\xcb\x13\x89\x25\xca\x10\x22\x18\x81\x5f\xba\x09\xa8\xcc\x90\xbf\xcb\x53\x79\xd6\x6e\x3f\x23\x5b\xe5\x5b\x88\xaa\x42\x7b\x58\x13\xb0\x26\xbb\x17\x5e\xac\x40\x79\x0a\xb8\xc7\x55\x02\xdf\x72\x13\x20\x56\x8d\x11\x48\x65\x32\xe1\x2a\xdb\x7d\x1a\x38\x3b\x3d\x83\x80\x21\x64\x57\x41\xc8\x88\x66\x5d\x58\xd8\x24\x76\x41\x66\x42\x7f\xb2\x02\x89\x94\x25\x46\xb6\x73\xa0\x10\xdb\xa5\xe2\x60\x22\xb8\xca\x9a\x29\x74\xb3\x67\xb5\x6c\x9f\x3e\x0b\xed\xb8\xdc\x60\xc1\xb2\xcc\xcd\x80\x34\xd2\x9b\x16\x12\x98\x83\x30\x86\x66\x40\x30\xc6\x34\x0b\xe0\xcb\xb4\xaa\x18\x2f\xd0\xc4\x67\x24\x5f\xa9\xb5\x30\xa1\x70\x6f\xf4\xa4\x40\x85\xbe\xa8\x70\x21\x9e\x99\x35\x09\xc4\xb2\xbe\x8a\x1d\x3f\xe1\x8c\xa7\x07\x5f\x94\x96\xc2\x88\xfa\x6a\xaf\x3b\x9f\x73\xd4\xf2\x02\x41\x14\xf4\x68\xaa\xcd\x07\xaa\xdf\xc0\x85\xea\x3c\x40\x18\x48\x4e\x33\x7b\x33\x54\xcc\x89\xe5\x50\x8c\x42\x29\x86\x85\x4b\x73\x18\x05\x78\x6e\x38\xc8\x7e\x78\x65\x46\x1e\xa9\xcc\x42\xe4\xd3\xa9\x90\xc3\x67\x17\xe1\x64\x68\xa6\xbd\x4e\xee\xda\xfd\x29\x5c\x19\x0d\x45\xbf\x38\xe0\xe3\x4a\x48\x7d\x14\x0d\x45\x76\x72\x6a\x81\x3c\x53\xe5\x13\x54\x7a\x9f\x50\xa3\xe5\xdf\x57\xf8\xcf\x48\xd5\x19\xf6\xe8\x2a\xac\x50\x66\xf9\xec\xe9\x0f\x31\x90\xdd\xd2\xfa\xdf\x67\x1c\x85\xf7\x45\x87\xc5\xae\x3f\x9f\x77\x21\x8d\x63\x8c\x8b\x08\xcb\x4e\x11\xa1\x88\x4c\x37\xf0\x02\x18\x7a\xfb\xb8\x83\x84\xa7\x61\xe4\x71\xa3\xbd\xa0\xf2\x40\x52\x4d\x00\x66\xff\x57\x10\xfc\x3b\x14\x37\xff\x0a\x45\xa4\x8a\x49\xd3\x0e\x47\x97\xc5\xa5\x27\x51\xc4\xf8\x5e\xaf\x43\x14\x76\x4e\x2b\x0b\x74\xad\x16\xda\xec\x18\x71\x04\x57\x9e\x82\x71\x26\xf0\x93\x06\x16\x72\xad\xc8\xa9\x04\x75\x56\xa3\x92\x59\x63\x39\x3b\xf7\x55\xcd\x1e\xa2\x14\x06\xe8\x3a\x28\xd9\x1d\x48\x03\x09\x5a\x8a\xad\xd0\x15\x73\x38\x20\xea\x20\x15\x77\x23\x11\xd6\x95\x6a\x8a\x2d\x59\x06\x07\x71\x1d\xc0\xf2\x9d\xc9\xe4\x2f\x4e\x61\x2b\x00\x81\xd7\x81\xac\x5e\xa3\x4c\xfe\xea\x9c\x76\x01\x2c\x04\x75\x80\x17\x2f\x56\x26\x7f\x79\x96\xbb\x04\x1c\xc2\x3a\xf0\xcb\x37\x2d\x93\x85\x13\xdf\x11\xf8\x30\x83\x09\x5c\xc3\x10\x5a\x70\x05\x17\x95\x2e\x96\x4a\xeb\x3a\x51\xcc\x07\xcd\x66\x20\xd8\x04\x62\x76\x0d\x9c\x19\xdd\xb3\x05\x21\xbb\x82\x88\x5d\xc0\x63\xc6\x18\x91\x6c\x44\xeb\x2e\x76\x42\xd4\x74\xb5\x93\x44\x69\x20\xe0\xe2\x99\x74\xd2\x7c\x25\xc0\x68\x42\xbc\xeb\x94\xf4\x2d\x0a\x17\x2b\x76\xa1\xc3\x7b\xe5\xca\x30\x5d\x59\x77\xb3\x52\xf7\x7c\x65\xdd\xad\x72\xdd\x9a\x08\xed\x52\xd5\x6d\x53\x55\x41\xe4\xdd\x8f\xb0\x85\x4e\x2a\x6c\xe0\xa6\xc4\xa7\x1d\x23\xef\xa6\xda\x61\x4c\x0e\x9c\xa9\xe3\xc9\x86\xfd\x6f\x26\x01\xdd\x5f\xad\xc1\x98\x5c\x29\x30\xaa\x0d\xd1\x4c\x42\xcc\xce\x23\x8c\x1b\x8a\xf0\xfa\x9e\x70\x5b\xc0\xbd\x78\x70\x4b\x66\x01\xc4\x7b\x5b\x83\xb1\xf2\x6e\x15\xdc\x05\x46\xcd\x16\xc6\x8c\x1f\x13\x15\xa6\x87\x91\x09\xa5\x5e\x7a\x61\xc0\x2c\x47\xca\x41\xee\x14\x8c\x1b\x35\x99\x63\x82\x2e\x28\x8a\xfe\xf8\x84\xc2\x6d\xe3\x9c\x05\x91\x21\x03\x37\x88\x28\x70\x63\x26\xf0\x10\xf8\xb9\xf9\x7b\x5e\x99\x0c\xe4\xba\x25\xbd\xf3\x3e\x29\x5d\x50\xc8\x7d\xf8\x1c\xdd\x36\x2d\x88\x99\x76\x25\x46\x96\x47\x78\xb2\xcb\x37\x9d\x75\xc6\x44\x66\x6c\xaa\x53\x71\x36\x9f\x13\xf3\x87\xdd\x27\xb4\x6f\x56\x8d\x31\x26\xda\x6d\x27\x98\xf0\xd9\xcc\x3c\xc4\x83\x03\x45\x02\x7b\x3f\x3a\x30\x5a\x2b\x47\x5f\xa1\xad\x70\xc4\xaf\x44\x5e\x49\x41\x0c\x97\x92\x70\x33\x4b\xa6\x22\xfe\x2e\xfc\x34\xc5\xa9\xcf\x82\xde\x2f\x4f\xd5\x59\xdf\xfc\xc3\xc4\x40\x74\x9c\x35\xa7\xa3\xbd\x52\xb2\x8c\x67\xaa\x7a\x3e\xd1\xca\xbc\x9c\x79\x10\xa3\xa9\xe1\x8e\xf1\x96\xce\x98\x49\xf7\x8a\x50\x9a\x9e\xe7\x75\xcb\xd5\x42\xe5\x06\x4a\x70\x8d\x7e\x18\xa3\x32\xd8\xeb\x91\xe1\x88\x6c\x63\xb5\xd2\x11\x9c\x74\xc7\x68\x49\x5e\xf6\x4d\x91\x70\x5b\x7d\xba\x74\x5c\x1b\x0f\x62\x76\x1a\x83\x70\x2f\xcf\xbc\x3c\xd2\xe8\x92\xe2\xdd\xbe\x71\x7a\x2a\x7b\x7f\xe9\xc5\x30\xf5\x54\xe6\x59\x27\x01\x7b\xa6\x88\x00\x63\xaa\x8b\xc9\xd5\x4f\x71\x2d\xa4\xfe\x69\x54\x9a\x9f\x4a\x8c\x18\x87\x20\x09\x47\x64\xab\x8c\xf5\xa1\x22\xc6\x8e\xbd\x20\xd2\x3d\xa7\xa0\x40\xba\x43\x0a\x41\xdf\x2e\xa0\x74\x47\x83\x7c\x58\x07\x13\x61\x54\xac\xa3\x8f\x44\xba\x23\xc0\xd8\x83\xc5\x32\x8c\x48\xe8\x07\xaa\xdd\x76\xb8\xd9\x43\x6e\xd0\x6e\x07\x35\x4e\xc9\x60\x12\x06\x63\x07\x02\x45\x02\x4a\xc1\xa0\x90\xf6\xdc\x2f\x9f\xf2\x0a\x88\x58\xb7\x1f\xed\x85\x99\x2a\x1b\x75\x3a\x34\x32\x95\x9f\x29\xd2\x33\x83\x18\x84\xa7\xd1\x99\x67\xfe\xc1\x13\xdb\x5c\xc1\x0d\x4a\x97\xed\xd4\xd2\x09\xa8\x31\xfe\x74\xd9\xd1\xd8\x37\x6c\xca\x2c\xc4\xe0\x48\xa1\xbf\xd6\x4b\xf7\xb7\x18\xbc\xb2\xcd\xf1\x95\x25\xde\xc1\x65\x5e\x67\xdb\xbe\xf8\x98\xbe\x20\xce\x35\x9f\xc4\x02\xb7\xc0\x7c\xee\x04\x17\x22\x18\xa3\xb6\x6a\x1e\xe5\xa9\x38\x5b\x67\x2c\x46\x5f\x16\x7a\x3e\xca\x87\x64\x47\x0b\x44\x38\xd3\x77\x13\xd1\x78\x55\xa9\x74\x26\xa5\x16\xd4\x30\x5b\xb3\x74\xf5\xa0\x2f\x06\xe8\x02\xdb\xd7\x5a\x85\x7e\xac\x05\xb1\xb9\x10\x5c\x25\xae\xa2\x6b\x51\x7a\x5d\xc6\xe7\xe3\x1f\xe1\x82\x51\x96\x47\xc0\x99\x70\xa3\x3e\x5f\xe8\xe3\xe8\x23\x89\x41\x63\xca\x83\xc5\x7e\x6c\x51\xb9\xaf\x57\x8b\xfb\xd5\x90\xee\xe1\x0c\xf7\x1b\xfe\x42\xde\x51\x31\xdd\xf5\xc2\x25\x1b\x63\x96\x9b\x8d\xc6\x6d\x28\xa3\xfd\xd7\xfd\xe5\xb6\x18\x63\x1c\x8d\x70\xf7\x17\xe3\xfd\x20\x92\x3a\x94\xb1\x48\x32\xac\xaa\x64\x19\x1b\xfd\x20\x60\x6f\x0d\xab\xe1\xb5\xde\xf4\x18\x02\xb8\x53\xed\xf6\xfd\x94\xcf\x66\xe1\xb5\xf0\xce\x23\xc2\xe9\xde\x66\x42\x01\xaf\x3b\x05\xf6\x9c\xa3\x19\xbc\xad\x96\xe9\x96\x5a\xdd\xdd\xdf\x84\x72\x18\xdd\xd4\x39\xfb\x1d\x7b\x3e\x79\x8c\x7c\xc1\xb5\xb6\x4f\x1e\x6a\x71\x9f\x80\x93\x22\xe1\xc0\xfd\xb9\xd0\x5e\x49\x6f\xb8\x53\x6c\xbd\x6b\x64\x73\xe1\xd5\x2d\xa6\xfb\xad\x22\x3e\x18\x1e\x5f\xf2\xa9\xe5\x46\xad\xfb\x0b\x34\xbb\x43\x99\x02\x32\x0b\x59\xd0\xb4\x1a\x3c\x7b\x1e\x11\x45\x91\xeb\x73\x08\x58\x3c\x30\x72\x8d\xbb\xdc\xe3\x6e\x10\x79\x1c\x42\xd6\x33\x1c\x9b\xbb\xbe\xb7\xc5\x58\xdc\x6e\x73\x23\x6c\x22\x46\xc2\x76\xdb\x50\x76\x34\x35\xa3\xe0\xe7\xdc\x62\x0b\x64\x73\xa9\xfa\x39\x35\x55\xa7\x0a\xf9\xd7\x73\x31\xe2\xf1\x44\x13\x0a\x3e\xed\x0b\x16\xb9\x97\x7d\x7b\x11\x2f\x1b\x41\x11\x60\x25\xa8\x31\x9b\x03\x6a\x23\xac\x97\xe3\x73\xfb\xa3\x8d\x8d\xbe\xa9\x73\x3a\x3a\x33\xd5\x22\x16\xb9\xd3\x24\x22\xa8\xb8\x65\xa2\x64\xe6\xfe\x62\x12\x66\xa5\x23\xd8\xca\xe6\x3c\xcd\x6f\x0a\x1e\x67\x1e\x9f\x2e\x2d\x67\x5f\xfa\xad\x16\xad\xca\xfb\x96\xa7\x40\x79\x1a\x66\x9e\x00\x9d\x9a\x16\x10\x67\x36\x46\xe1\xb8\x4e\x2d\x23\x28\x5d\xeb\x3d\x2e\x41\x0b\x47\x04\x6f\x4b\x64\x70\xa5\xd1\x2e\x8c\x12\x82\x01\xf1\xeb\x8c\x59\xfa\xef\x19\x3e\x33\x9f\x6f\xe2\x8b\xb2\x3b\xe6\xb7\x22\x1a\xba\x20\x30\xb8\x85\xd5\x3b\x9a\x0c\xdb\xfd\xcb\x2c\x0e\x46\x0a\xe7\xe9\x38\x52\xe3\x52\xba\xc6\x76\x93\xee\x10\x84\x27\x60\xe4\x19\x51\xe1\x7b\xd2\xf5\x93\xc4\x12\x4d\x2f\x49\x9d\x63\x3c\x75\x8d\xed\x94\xbc\x4c\xd2\x9d\xd8\x78\x6c\x88\x58\x90\xc7\x87\xb0\x88\x31\x96\x0b\x81\x51\xbb\x1d\x99\x55\x1c\xb1\xe0\x34\x3a\x33\x25\xa7\x11\x6e\xfe\xd1\xc2\x89\xa6\x91\xd5\x63\xda\x37\x3f\x94\x11\xda\x7d\x1b\xa5\x53\x5d\x3f\x77\x0c\xca\x1d\x83\x6f\xd6\x10\xdb\x75\xf7\xfc\xfc\x8a\x13\xce\x57\x0f\x04\xf8\x34\x0f\x08\xcc\x90\x9d\x19\xf1\x0d\x13\xa6\xdc\x4b\xb8\x66\xeb\x3d\x18\x9a\xee\x50\x9e\x0f\x8d\x3c\xbf\x66\xeb\x5d\x58\x12\xea\xb3\xc1\x8c\x9d\xce\x60\x68\x84\xfa\xcc\x2e\xf7\xd0\x08\xf5\x21\x1b\xba\xe3\x9c\xc7\xb5\x98\x4a\x41\xb5\x9a\x41\x4d\x06\x13\x76\x3a\x81\x96\x01\x35\xb1\xa0\x5a\x06\x54\x8b\xb5\xdc\x71\xee\x0c\x6c\xb7\xb3\x98\xea\x75\xc6\x26\xd9\xdd\x93\x45\x6a\xf0\x08\xb9\x1e\x34\x19\xf6\xdd\xbe\xde\x2b\xf2\x46\xd8\x68\x0c\x79\xaa\x8d\x34\xc3\x08\xbb\xe5\x50\x0c\x32\x83\x09\xf5\x66\x8c\xb1\x09\x9d\xcf\xb1\x9f\x4d\x10\x30\xb1\x53\x6c\xe6\xdd\x58\x3b\x1a\x44\xa7\xb7\x14\xc3\x84\x8b\x20\x5d\x8e\xb1\x21\x3c\x5d\x83\x2d\x74\x78\xf3\xa5\x90\x28\x04\xf7\x34\xdf\x21\x70\xb2\x18\x3b\xba\x54\xe3\x79\x56\x63\xcb\xc3\x63\xba\x0b\xec\xe7\xa2\x71\x9b\x60\x00\x35\xfb\x64\x28\x65\x08\xca\x68\x28\x57\x29\x4e\xdb\x20\xe0\x2a\x8d\x99\x66\xca\x0d\x8b\xe0\x99\xf2\x48\x32\x2a\xda\x01\x01\x17\x94\x96\x7d\xdd\x25\xac\x62\xbb\xb7\xb3\xc8\x20\xc3\xfc\xd2\xb0\x9c\x4c\xd0\x95\x31\xe0\x25\x0c\xb8\xb1\xbe\x73\xfb\x1e\xd9\x5e\x09\xfd\xd2\xad\xe9\xaa\x90\x35\xfa\x76\x35\xa2\x0f\xef\xe2\x1b\x3d\x68\x9d\xb1\xc0\xe8\x6f\xdd\xfc\xd7\x56\xfe\x6b\x1b\x7f\x99\x9a\x41\x49\x21\x08\x99\x3c\x0d\xce\x20\xb2\xb9\x4d\x42\xc6\x58\xd4\x6e\x17\xba\x90\x69\x59\xd2\x85\x82\xf9\x3c\xd5\xae\x74\xbb\x4d\x48\xcc\x42\x6a\xe4\x34\xe1\x2c\xa2\x6e\x0b\x03\x8c\xf2\xac\x14\xf3\x39\x21\xc2\x68\x4f\xf7\x09\x3d\x0d\xce\x58\x64\x87\x58\x79\xa7\x07\xa9\xf6\xa6\x07\x8e\x93\x29\x6e\xda\x74\xb2\x65\xdf\x5a\x2e\x8b\xc6\xdf\x69\x70\xe6\x8e\x20\xca\x18\xaf\xb7\x7c\x97\xfb\x34\x38\x33\x60\x8c\xe4\x45\x21\x72\x6f\x05\x88\x99\x3e\x33\x46\x33\x42\xd3\x33\x04\xd4\x30\xa2\x2a\x76\x23\x9a\xe4\xc1\x80\x76\x7a\xf0\x8f\xac\x8c\xc2\x37\x7c\xd3\x2f\xe7\xbe\x29\xc2\x68\x96\x04\x87\x61\xc6\x86\xc1\x0b\x23\x67\x8b\x8b\x6e\x3c\x0f\xa2\xda\x0b\x06\xb8\xdc\xbb\x20\xe0\xfe\xda\x0b\x21\xf4\x82\x8d\x30\xa1\x5e\xb0\x17\xa6\x54\xf2\xc8\x16\x05\x20\x3c\x5e\xd2\xa3\x22\x16\xec\x85\x83\xc0\x0b\xb3\x20\x4a\x1b\x3d\x69\x79\x64\x7c\x3a\x3a\xeb\x1f\x1b\x45\x81\x9f\x8e\xce\x40\x43\xa7\x63\x2f\x5a\x5a\x1f\x5e\x89\x88\x9f\x97\x70\x2e\xe7\x62\x01\xce\xcc\x2c\x99\x5f\x99\x2a\x6f\x86\x31\xca\xf9\x38\xf8\x2c\x8b\xdb\x84\x19\xeb\xc2\x84\x75\xe1\x9a\x89\xfe\x6c\x6f\xd4\x6e\x4f\xf6\xfc\x34\x12\x60\xc8\xc8\x33\x16\x9e\xce\xce\xa8\xcb\xa1\xc5\xc8\x21\x8b\x4e\x27\xf8\x70\xc5\x9e\xb9\x3e\x5c\xb0\x43\xd7\x37\xdc\x7f\xb8\xce\x58\xcb\xb6\x99\x9a\x06\x9d\xde\x19\x9c\x9b\xca\x9d\x1e\x4a\x87\x29\x35\x45\x37\x6c\xea\x72\xb8\x63\x53\xd7\x87\x31\x33\xea\xe1\x8d\x29\x3c\xc7\xc2\x5b\x76\xee\x72\xd8\x67\xe7\xae\x0f\x07\x6c\xc8\x18\xbb\x35\x85\x07\xed\xf6\x98\x1e\x2b\x72\x05\xfb\x10\x43\xa7\x73\x4d\xe1\x97\xc2\x6c\x79\x43\xb8\x80\x89\xd1\xea\xae\x3b\xec\xca\x7a\x37\xdf\x67\x25\x77\xb6\xe6\x75\x87\xdd\xd9\x92\x59\x87\x6d\xc2\xa4\xc3\x36\xad\x72\x62\x00\xd3\xeb\x4e\x27\x83\xd5\xca\x60\xe5\x3d\x5d\x97\xe1\xce\x3a\xac\x57\x6d\x3d\xa6\x79\x5f\x57\x79\x5f\x69\xed\x63\x45\xee\xe0\x22\xc3\x76\x19\x87\x5e\x3f\x0b\x05\x5a\x9f\xce\xe7\x37\xeb\x8c\xdd\xa6\x77\x60\x16\x61\x2e\x62\xb7\xd0\xc7\x7e\x73\x1f\x9b\x89\x65\x47\x38\x9e\x32\x2e\xf9\x88\x3a\x30\xe9\x74\x70\xcb\x98\x55\x4f\x17\xfc\x59\x86\x42\x69\xdd\xed\x52\x2f\xb7\xb7\x6d\x0b\x62\x39\x84\x23\x76\x34\x9f\x9f\x9e\xf5\x53\xb4\x4b\xe4\x72\xe8\xfa\x90\x2a\x5e\x47\x14\x3b\x26\xdd\xbd\x6c\x4f\xcd\xe7\xdd\xbd\x20\xff\x7d\x44\xd3\xad\xf3\xd8\x6c\x9d\x1b\x2f\x86\x5b\x2f\x80\x3b\xef\x28\x3d\xb9\x7a\xa9\x98\xf3\x53\x4c\xae\xbe\xee\x3e\x7d\x5b\x4a\xce\xf9\x4b\xd5\x1d\xb8\x1b\x49\x89\xd1\x30\x41\x26\x63\xd2\x23\x96\x7b\xe5\xc5\xb0\xef\x05\xec\x3e\xf0\xba\xf0\xdb\x13\x60\x5e\xcc\x72\xc7\x73\xaa\x8f\x98\xf6\x2c\x40\x55\xdc\x98\xbc\x81\x1b\xe4\x87\x34\x19\x84\x84\x42\xe0\x06\x6c\x33\x3d\xb3\xaf\x28\x38\x81\xfb\x1b\x04\x84\x10\xb8\xca\xd4\x52\x2c\xb6\x60\x03\x77\xe6\xce\xd8\xfd\x8d\x17\x5a\x08\x49\x86\x7d\xe7\xa5\xca\xbc\xb0\xf9\xc8\xde\x57\x24\x95\x15\x48\xd9\xb8\x78\x1e\x0b\xc6\x2d\x6a\x19\x22\x41\x15\x11\x01\xdc\xfd\x0d\x01\xc4\xa9\x12\xf0\xdb\x58\x59\x4f\x20\x36\x13\x1c\xc0\xbe\xe1\x4d\xc9\xfb\x2a\x0e\x96\xd9\xa7\x22\x26\xaf\x9f\x1d\x00\xe0\xc4\xdc\x07\x5e\xaf\x34\x77\x61\x59\xbe\x7e\x29\xb1\xa6\xf5\xd2\x61\xfc\x82\xc3\xd7\x32\x43\xb4\x20\x2d\xaf\x8f\x5c\x1b\xaf\xd4\x37\x22\x38\xbb\x4c\x6c\xb8\x55\x2b\x5b\x04\x9f\x7e\x31\xd8\x68\x77\x0c\x91\x3b\x83\x90\xe6\x9b\xf2\x31\x96\xde\x47\xae\x66\x0a\x22\x37\x66\x61\xdf\x2a\x8b\x91\x3b\x73\x6f\xfa\xdd\xbd\x59\xae\x5c\x5a\x44\x66\xd0\xcd\x1c\xc7\x19\x8c\x27\xf5\x30\x26\x06\x86\xc1\x60\x42\xef\x27\xee\xbe\x3b\x63\x2a\x85\x3d\xf9\x13\x64\x0b\xba\x0c\xd0\x10\x24\x31\xa3\xee\x74\xf0\x64\x98\xe0\xb0\xe9\xbf\x73\x22\x8d\x91\xd2\xaf\x99\xb6\xa3\x36\xba\xe8\x75\xc1\xe1\x87\x4c\x97\x75\x5d\xab\xbd\x16\xc7\x1f\x30\xb4\x13\xdc\xe9\x41\x00\xaa\xc6\x13\x65\xf7\x51\x8b\x69\x57\xa4\x1a\x96\x72\x83\x8b\x70\x32\x3c\x8a\x86\x62\x96\xcb\xa8\x0b\xd6\xed\x5f\xec\xb5\x32\x69\x77\x91\x09\xa8\xa9\xb1\x30\xd9\xf5\xa0\x75\x7a\x71\xe6\x99\x7f\x5c\x1f\xce\x59\xa7\xc3\x3b\x64\x6a\xcf\x79\x90\x32\xf7\xd8\xa8\xdd\x1e\xed\xb1\x73\x4c\xd4\x26\xc9\xd5\xe9\xc5\x19\x4c\xd3\xb5\x3f\x87\x90\x82\x9d\x83\x85\x19\xc8\xa7\xa0\xcf\xd9\x79\x7e\xd7\x2f\xc9\x6c\x3d\xe8\x82\x72\x7d\x28\x27\x91\x7c\xad\x96\xce\x64\xd0\x33\x98\xa9\xdb\xd2\x23\x25\x62\x84\x77\x0a\xef\xf9\x96\x00\xbc\x5b\x74\xb7\xa0\xd2\xad\xca\x4a\xf7\xa2\xeb\x45\x03\x67\x2f\x14\x89\x31\x5b\x14\x63\x4c\x62\x82\xa5\xc2\x21\x5a\x0a\x5c\x7e\xa1\x2a\xf7\xb2\x54\x29\xbc\x7d\xe9\x00\xb6\xea\x88\x29\x8e\x3f\x21\x66\xcf\x90\xe6\x69\x3f\xae\x59\xd0\xf9\x9c\xd4\xbd\xb6\xbe\x9c\xc5\xc5\xef\x8b\x76\xdb\x58\xab\xb2\xdd\x5e\x38\x56\x8d\x41\x96\x52\x5b\x61\xec\xc0\x0c\x94\x1b\x2f\x5c\xc7\x4a\x9d\x7a\x6e\x6c\xca\x29\x2c\x86\x1e\xc8\x0c\xe8\x73\xae\x39\xe9\x42\x9e\x32\xa0\x5c\x3b\xb7\x21\xec\xdc\xbb\xb3\x45\xcb\xa1\x0e\xf5\x41\xdd\x4b\xf7\x92\x29\x77\xe6\xd5\x15\xb1\xfb\x4b\xcf\x0c\x61\xea\x29\x37\x4e\xb2\xae\x77\xbd\x72\xf4\xdc\x2c\xcd\x77\xa9\xdd\x10\x63\xdd\x33\xe7\x91\x9d\x11\x59\xda\x17\xa7\xda\xbd\x2e\x14\x47\x99\xdd\x1f\x28\xd4\x2e\x82\xf0\x28\x2a\x8d\x95\x86\x82\x99\xa6\x7d\x91\x0b\xbc\xb4\xa7\x50\xce\x84\xd2\x4f\xc5\x28\x52\x82\x3c\x53\x24\xc6\x00\x7b\x37\xa6\xc0\x17\xfb\x79\xe2\x21\xcf\xb0\x3d\xd0\xc2\x63\x51\x3e\x20\x2f\xa1\x6d\xe6\xd9\x4a\x01\xed\xee\x97\x2d\xa2\xb5\xae\xb1\x01\x5c\x85\x0e\x9e\xc6\xc6\x81\x3b\x63\x76\x9b\xb8\x37\xf9\x92\x3d\xae\x23\xd7\x22\x1d\x81\x99\xc8\xe5\x70\xdf\x2c\x08\xb5\x14\x82\x9a\x7b\xad\x9f\xa7\x51\x03\x87\x8a\x9f\xa3\xfb\x3a\xcf\x3d\x5a\x9e\xa6\x4c\x17\xcf\x22\x52\xf7\xfb\x11\x5a\xb4\x56\xe4\x0d\xb8\x3b\xf3\x9e\x29\x62\xa4\x9b\x99\xb9\x72\xec\x9a\x76\xef\x6c\xce\xa7\x7c\x28\x85\x1b\x93\x69\xf7\x36\xbd\x76\x93\x2f\x4a\xe9\xf6\x4d\x7c\xca\x8d\xe6\x1c\xb8\xfb\x10\xb1\x4d\xf4\x7f\x04\x83\xd0\x76\x15\xa6\x5d\xf5\x17\x16\x30\x82\xca\xa2\x07\xae\x3a\xa3\x89\x68\xb7\x31\x0e\x42\x94\x02\x86\x70\x76\x16\xee\x0a\x2a\x77\x46\x24\xed\x0f\xad\xb3\xcd\x7b\x46\x7a\xdd\xb2\x93\xf6\xb3\x4a\x03\xdf\x6d\x5e\x5d\x43\xe0\x9f\xee\xa6\x22\x23\x84\x91\x31\x4f\xb5\xb8\xd5\x69\x68\xa5\xd5\x57\xd6\x1b\xaa\x3a\x0e\xed\x2f\xe6\xa5\xe4\x99\x83\x78\xb6\x2a\x24\xb8\xaf\xd8\x15\x19\x93\x73\x05\xb1\x2b\xf9\x95\x80\xd8\x45\x3b\x13\x53\x14\xa5\x8a\x89\xab\xf9\xf9\x11\xbf\x12\xae\x8e\xde\x46\x37\x42\x3d\xe3\x33\x41\x68\x7a\x62\x2a\x17\xe5\x8c\x28\x3c\x4b\xc2\x3a\x07\xaf\xc8\x67\x45\xc2\x53\x71\x46\x8d\x95\x97\x1f\xa2\xfb\x0a\x38\x28\x08\x2a\xe1\x23\x0a\x24\xe8\xd2\xb1\x31\x06\x5d\x86\xa0\xdc\xe0\xdc\xfc\x73\x6c\xfe\x29\x85\x6d\x62\x02\xc4\x2c\x2c\x22\xf8\x00\x9c\x85\x38\x3f\x10\xb0\xcf\x8a\x14\x7b\xee\xab\x5a\xb8\xa0\x6f\x67\x2a\xc6\xdc\x8a\xec\x27\x9e\x97\xd0\x3e\x67\xaf\x8d\x9a\x1b\x58\xa9\x12\x30\x0c\xc1\x4b\x4f\x0d\xbf\x57\x22\x06\x2c\x9a\xa2\x8a\xa6\x68\x44\x33\xce\xd0\x34\xb6\xe7\xbb\x76\x5b\xb9\xef\x08\xe6\x32\x45\xa4\x43\xb3\x81\x74\xa8\x27\xc6\xa8\x0b\x15\x46\x21\xc3\xc8\x0c\x20\x6a\x1e\x40\xa0\x18\xef\xdb\x51\x04\x76\x14\xbe\x22\x8e\x69\xea\x50\xd2\xa2\x44\xb9\xfe\x07\xb3\xfb\x7e\x2a\x32\x32\x42\x26\x32\x63\x8b\x60\x84\x7a\x20\x8c\x98\x86\x40\xb1\x2e\x84\xe8\xae\x09\xde\xb6\xdb\x24\x43\x82\x85\xf8\x86\xda\xc1\xc3\x87\xfa\x48\x21\x65\x23\x80\xf7\x65\x78\x85\x7e\xe7\x43\xc5\xaf\xc4\xa0\xf6\x6d\x25\xd8\xa9\x14\xe6\x25\xa1\x27\xb6\x1e\xee\x76\x69\x29\xc4\xe8\xab\xb2\xa1\xc0\x82\xe8\x2c\x62\xbb\x74\x2f\x86\x13\x7a\x1f\xa3\xae\x12\x0f\xba\x1e\xf9\x60\x96\x18\x4c\x55\xe8\xe5\x6c\xa2\xca\xb1\x34\x93\xa0\x06\x04\xeb\x98\x5d\x6f\x73\xcc\xf6\x28\xf5\x50\xc5\x8e\xdb\x6d\x0b\x24\x66\x9b\xe5\xdd\xf9\x4d\x15\xd1\x02\x97\x91\x99\x9a\x49\x14\xe0\x88\xdc\x0b\x23\x71\x5d\x3e\x9f\x3f\x23\x3d\xda\x14\xcd\x32\x26\xd3\x08\x2e\xa2\x4a\xa4\x1b\xbd\x57\xed\xf6\x45\x38\xd3\x91\xba\x73\xad\xcb\x5f\x12\x9b\xd4\x13\x47\xfa\xa3\xf1\x50\xba\x1e\x5a\x06\xca\x98\x2e\x1f\x35\xd7\x02\xcf\x30\x1c\x28\xc1\x85\x37\xaa\x31\xc7\xc7\x6a\xa0\xa9\xc0\x6f\x82\x7b\xbf\x78\xbc\x52\x3e\x2d\x49\xa0\xe6\xb4\xc6\xab\x06\x56\x83\xd4\x8c\xac\x8a\x40\x6b\xb7\xb3\x5f\x50\x57\xcd\x9e\xf2\x0c\xec\x1f\xef\x8d\xaa\x44\x2c\x54\x35\xc7\xe7\x92\x54\xc7\x58\x32\x5d\x24\xbd\x3f\x91\x44\x60\x64\x5c\xce\xb7\x97\x8e\x8e\x34\xc8\xea\x29\x15\x66\x0c\x2b\x2f\x6c\xed\xf9\x94\xb6\xdf\x7e\x68\xce\xea\x92\xde\xef\x2f\x5d\x47\xd0\x74\x70\xa4\x89\x76\x39\xe6\xf7\x28\x85\x11\x28\x5d\x0e\x91\x5f\xbc\xae\xf3\x41\x95\xc7\x87\x31\x28\x2c\x9b\x3e\xf7\x5c\xe8\xf4\x34\xf9\xe9\xdd\xab\x21\x5e\x7f\x20\x72\xf0\x36\x1d\xb6\xf7\x53\x92\xab\x28\x4f\x0c\x82\x3c\x5f\xeb\x6a\x78\x73\x29\x8a\x50\x2f\xb0\xa1\x4c\x04\x9e\xaa\x33\x42\xe1\xf7\xaa\x00\x67\xcd\x6a\x42\xbb\xb4\x3b\x0b\x54\x34\x99\xd8\x9c\x3b\xbf\x93\xc5\xd8\xd0\xea\xc8\x30\x1a\x54\x13\x5a\xba\x55\xa6\x57\x04\xab\x34\xa3\x9b\xf6\xfa\x56\x8c\x8c\x09\x97\x3d\x7e\x8a\xa6\x4c\xaf\x1e\x84\x5c\x9d\x97\x6b\x55\xe1\xff\x5c\x91\x57\x52\xed\xed\xd5\x65\x27\xcb\x4a\xff\xfd\xef\xd5\xa5\xa6\xb8\x29\x16\xb4\x4a\xfb\x96\x36\x66\x42\xbf\x92\x5a\xa8\x6b\x3e\x29\x17\x9e\x48\xa2\xf1\xb6\x4e\x53\xa4\x6d\xde\x48\xa6\x37\x38\xd0\xae\xd1\x10\x6b\xe0\x1a\x02\x0d\xa1\x86\x48\xc3\x48\x83\xaf\x61\xa6\xd9\xf2\xd4\x17\x71\x9b\x30\x69\x28\xdf\x4c\xcb\xaf\x1b\xca\xb7\xd2\xf2\x61\x43\xf9\x76\x5a\xde\x6a\x28\xdf\x49\xcb\xaf\x34\xbb\x6f\x79\xbb\x09\x5c\x68\xf6\xa7\xd8\xb8\x7b\x1e\x78\x1a\xbe\x7a\x0a\xfc\x91\x27\xe0\xc8\x0b\xe0\xd8\xe3\xf0\xde\x8b\x21\x78\x8d\xb9\x5e\x60\xaa\x57\x64\x29\x23\x66\x66\x31\x7b\x8b\x66\x43\xb8\xd1\x8c\x88\xf2\xdd\x97\xd2\xf5\x08\xe5\x06\x98\xdc\x70\x08\xbc\x49\x1c\xdc\x92\x73\x0d\xd2\x6d\x0d\xb4\xc7\x31\xcc\x83\x9b\xa5\x28\x17\x72\xc0\x3f\x06\x70\x4c\x6d\x5e\xa9\x1e\x85\x3b\xcd\xba\x30\xd6\xec\x02\x6e\x35\xdb\x84\xfd\x3a\x84\xd1\x4f\x63\x8f\x83\x37\x36\xd1\xe4\x6e\x55\x53\xaf\x1a\x5d\x72\x08\x31\x93\xc0\xd9\x2d\x2a\xe1\x3e\x68\x37\x80\x5b\xb2\x8f\xe3\x00\xed\x0a\xcc\xcb\x1b\x83\x62\x1c\x34\x13\x66\x72\x0e\xea\xd6\x62\x0d\xdb\x34\x4e\xda\x98\x8c\x35\xd8\x14\xb7\x36\x89\x57\xcb\xf0\x53\x78\x56\x05\x85\x2a\x50\x9e\x8e\x89\x49\xf8\x0b\xa0\x32\x83\xa7\x68\x02\x87\x9a\x7d\x84\xa3\x3f\xd0\xea\x25\xd2\x4a\x2f\x81\x8f\xd5\x8a\x78\xc8\xe4\x97\xef\xbf\xc9\x52\x26\x84\x4b\x9d\xc0\x2b\xdd\x98\x36\x11\xc3\x5a\xe1\x6d\xed\xd4\xc8\x04\x7e\x6a\xf6\x13\x7e\x2f\x37\x97\xde\xe2\x22\x15\x77\xee\xd7\x2e\x75\x3f\x33\xdf\x02\xcc\xf1\x3a\x44\x6a\x12\xd9\x55\xfc\x31\xf9\x89\xcb\xe4\xfa\x34\xf7\x59\x48\xa3\x23\x31\x91\x47\x73\xac\x2d\x5a\xf4\x47\x98\x60\x33\xb3\x64\x6c\xf5\xb8\x54\x3d\x31\x4b\x7c\xdc\x38\x50\xe5\xb6\x06\xd2\x53\x2e\x4f\x28\x3c\xd5\x4d\x37\x67\x6a\x26\x41\x93\x31\x39\xd6\xd0\x82\x31\xf9\x6d\x3f\x6e\x82\x01\xec\xf0\x69\x65\x57\x97\xda\x33\xeb\x60\x83\xf7\x13\x0a\x27\xf5\x13\x5c\xb5\x66\x12\x78\x5e\x5b\x6d\x4c\x9e\x9a\xf9\x1a\x93\xa9\x86\x8f\x1a\x3e\x19\x94\xa6\x1a\x4e\x34\x1c\x6a\xe2\x8c\xf8\x64\x26\x1c\x6a\xfe\x2f\x81\x97\xcd\x58\xd9\x0c\x6a\xbf\x34\xfb\x06\xef\xff\xb0\xeb\xd6\xf5\x62\xb2\x63\x81\x19\xe8\xed\x8e\xc3\x2f\x48\x64\x89\x8f\x2b\x3b\xec\x4b\xc3\x0e\x7b\xaf\x61\xac\xd3\xad\xf3\x5a\xd7\x46\x3d\x87\x23\x22\x8a\xf0\x72\xe1\x72\x0c\x42\xc2\x43\x20\x9e\xbd\x0f\x18\x77\x39\x9e\x94\xe1\xfb\x30\x7b\x1f\xb1\x10\xef\xb0\x85\xf6\xfd\x28\x7b\xef\xb3\x51\xf1\x61\x11\x83\x75\x0c\xe6\xdf\x00\xff\x8d\xf0\xdf\x91\xcb\x61\xa7\xdb\xdd\xd3\x03\xc4\xd2\xa0\x63\xf3\x74\x78\xfb\xe4\x75\xca\x4b\x3a\x3d\xf0\xed\xf4\x36\x82\x52\x0d\xa5\x6a\xf1\x75\x35\xe7\xee\xbb\x15\xec\x3a\xef\xbf\x6b\x19\xc5\x8b\xca\xca\x96\xf3\xf7\xdf\x92\x77\xba\x49\x2e\x23\xab\xb1\xf9\xd9\x73\xee\x45\xe1\xb3\x6e\xc8\xc8\x99\xf2\x9c\xd8\x13\x70\xe3\x69\xd0\x46\xd6\x1c\xe2\x51\x09\x8a\x97\xef\x8d\xd4\x75\x43\x3e\x6b\x50\xee\x2d\x28\xd7\xfc\xbd\x41\x3f\x9e\x21\x7f\xff\x10\xe9\xff\x83\xae\xde\x3d\x90\xf9\x49\xca\x92\x98\x2f\xdd\x9a\xbb\x45\x27\x82\x06\xc1\xa4\x7b\x83\xb1\x95\x71\xb1\x9c\x2f\x34\x7c\x37\xac\xce\x3f\xa4\x10\x10\x8b\x40\x7e\x4e\x63\xf7\xe8\xd7\x15\x7b\xd4\x1f\xe0\xbc\x8d\xed\x9e\xf6\x8c\x6e\xf3\xad\xb1\xba\x66\xd8\x1f\x8a\x01\x6c\xf6\xd5\x90\xb3\xce\xb5\x3f\xf8\xb1\xdc\x34\x8d\xfa\x33\x0c\xb0\x6e\x8c\xf9\x38\xbe\x19\x9c\xb3\x7b\x31\xf0\xa6\x11\x87\x31\xf9\x61\x30\x20\x46\x59\xac\x9b\xac\x9b\x22\x5d\xee\x29\xce\x86\x99\x3f\x33\x7b\x46\x3a\xc7\x80\x2e\x53\xff\x90\x12\xcc\x44\x4a\xcf\xf0\xea\x7f\x86\xbe\x14\xec\x12\x54\xc9\xd3\x56\xf3\xd9\xa9\xd5\xeb\x82\xce\x49\xff\x10\x33\x80\x14\xfb\x55\xe3\x7e\xd5\xc5\x2e\x3c\x24\x01\x44\x74\x90\xa1\x88\xe4\x69\xb6\x09\x84\xe9\xc2\x9d\x51\xaf\x95\x6d\x91\x56\x92\x80\x16\x2b\x38\x62\x2d\x4b\xf5\xdb\xed\x75\xe9\xfa\xae\x3f\x48\x25\x21\x5a\x31\x09\x08\xc1\xc6\xe4\x83\x86\x0b\xd3\xed\x9b\x3f\xfd\xa3\x04\x71\xf8\x44\x28\x3d\x73\x28\x68\x41\x9c\x51\x38\xd1\x42\x39\xd4\x3e\x9d\xab\x28\x9e\x9a\x07\xc4\xc4\x09\xe2\x99\x8e\xae\x5e\x98\x97\xa1\x3c\x77\x72\x56\x7d\xa8\xc9\xa5\xb1\x6a\x6c\x23\x25\x02\x11\x5e\x5b\x20\xcf\x35\x71\x66\xe1\x44\xc8\x40\x0c\xb3\xe7\x50\x5e\x84\x7e\xa8\x8b\x17\x3c\xd0\xe1\x35\xf2\x76\x88\x0d\xf6\x15\xca\xf0\xff\x9b\x97\x08\x22\xe6\x13\x7b\x26\x19\x15\xb2\xbc\x95\x9f\x9f\xf1\x45\xfa\x5a\x5a\x3c\x32\x42\xba\x2a\x56\x8f\x82\x93\xa5\x3c\x3b\xd2\x14\xb8\x19\xc3\x0f\x3b\xb7\xe9\xd8\xcd\xec\xe2\xbb\x58\xe0\x6b\x31\x0c\x35\x8e\x37\x10\x8d\xac\xf1\x3e\x18\x7b\x12\xbe\x59\xde\xa4\x4d\x2f\xa1\x58\x56\xc7\xd0\x29\x98\x67\x45\xed\x16\x5f\xb4\xa9\xa6\x69\x57\x03\xe5\xf5\xba\x9b\xdb\x0f\x88\xda\xc0\x02\xda\xa9\x34\xec\xd1\x0d\xcc\xe7\xdd\xd9\xdd\xd9\xd9\xda\x4d\x20\xaa\xeb\x2a\x14\xa5\xab\x9b\x6a\x8f\xed\x3c\x6a\xb7\xb7\x1f\xef\x31\x95\xc0\xe8\x8f\xf5\x9f\x3c\xda\x63\x98\xdf\x8e\xf5\x36\x37\x13\xf0\xff\xa6\x83\x27\xdd\x76\x7b\x77\x07\x3b\x98\xd5\x6e\x90\x91\x69\x30\x9f\xfb\xf6\x8f\xf3\xd3\xb1\xb9\x47\x22\x81\x97\x00\x27\x82\x1d\x90\xd3\x63\xe2\xb0\xff\xe5\xc0\x26\x85\x63\xe2\xac\xff\x2f\x07\xb6\xf0\x17\x73\xa0\x6b\x5f\x31\x07\x7a\xf4\x8c\xc2\xb5\x60\xbf\x60\xd8\xb0\x11\xaf\x05\x48\x70\x1c\x9a\x40\xab\xae\x46\x91\xdd\x06\xae\x1a\xca\x33\xfd\xf6\x42\xa0\x7e\xdb\x4b\x60\x2a\x56\x24\xb7\x2c\x3e\x8f\x44\xe1\x7c\x05\x95\xa4\x80\x8b\x8f\x4d\x50\xb8\xf9\x5b\xb8\x77\x62\xc5\xd5\xac\x7b\xfe\xdb\xd0\xde\x37\x4f\x80\xef\x7b\x1a\xfc\x2b\x2b\x1d\xc7\x88\x7f\x37\x81\xdb\xa6\x6e\xd6\xc6\xe4\x46\xc0\x58\xc0\x3e\xb9\x13\x86\x1d\x5f\x19\xc3\xe9\x37\x72\xe8\x00\xe5\xe4\xbe\x60\x5c\xc2\x81\x60\xf5\x69\x09\x6a\xb6\xfa\x2d\xd9\x17\xc6\xc8\xc2\x7c\x0b\x85\xb3\xf9\x90\x28\xd8\xe8\xd1\xc1\x98\x4c\x05\xac\xf7\x60\x4c\x6e\xcd\x42\x09\x4a\x3d\x2c\xda\xa4\x83\x5b\x72\x2e\x60\xbd\x0b\x5d\x30\x23\xaa\xc6\x79\x62\x74\xa7\x51\x7c\xae\xcc\x8f\xab\x0e\xce\x8e\x51\x9e\xbd\x6a\x2b\x83\x7e\x67\xb1\xa9\xca\x9a\x65\x8d\xcc\xec\x3c\x6b\xa0\x9f\x03\x83\xd6\x85\x30\x46\x50\x75\xda\x4a\x66\x08\x85\xa3\xca\x42\x87\x85\xb1\x1a\x31\x09\xa3\x7a\x09\x6b\xe7\x27\x4a\x53\x3d\xf7\xaa\x36\x0a\xce\x0b\x7e\x7d\xce\xf5\x69\x6e\xae\x70\x34\x57\x8c\xa2\x3b\x22\xf8\xe5\x97\xb4\x61\xec\xb6\x32\xdf\x79\x5c\x30\x42\x84\xa1\xe7\x73\x0e\xb1\xeb\xd3\xc4\x96\xa5\x27\x3d\x6e\x50\x32\x86\xd3\x5a\x63\x82\x8c\xd2\xf5\x29\x04\x38\x27\x97\x8d\x84\x72\x4b\x8e\x04\x1c\xda\x8f\x25\x25\x14\x3e\x0a\x76\x29\xe0\xd5\x0a\xf2\xdd\x2c\x93\xef\xdb\xba\x6d\x51\x31\xd9\x72\x01\x90\x29\xf6\xa4\x8b\x29\x33\xd2\xc9\x2a\xc6\x6b\x9e\x08\x67\x31\x75\xf3\xa8\x63\xde\xb7\xd6\xd7\x98\xbc\x12\xa0\xc0\xa8\xe7\xc6\x00\x28\xdb\x62\x59\x4d\x16\x27\xe5\xb9\x5a\xef\x61\x92\x0c\x0a\x3f\x4b\xc4\xb0\xf2\xe3\x92\xb7\xe4\xad\x99\x84\x31\xc6\x3d\x26\xf0\x5b\xb0\x9f\x02\x8e\xff\xbe\xf5\xb9\xed\x14\x9d\xa0\xf0\x54\xb0\x63\x01\x9f\x56\xcc\x62\xb7\x3c\x8b\x27\x0d\x14\xfb\x49\xd8\x5c\x0f\x96\x6f\x19\xab\xad\xae\xe2\xba\x4c\xe0\x65\x5d\x81\x83\xbc\x38\x81\x5f\x82\xc5\x12\xde\x2f\xb3\x7b\x8e\x77\xb1\x02\xfc\xa8\x50\xc8\xd6\x5f\x8a\xd2\x19\xd2\x32\x7d\xdf\x90\x5f\x02\x78\xba\xff\x33\x86\x22\x31\xfb\x49\x85\xa0\x55\x41\x91\x87\x44\xd7\xf1\x86\x80\xa6\xbb\x3b\x4c\x37\x77\xbc\xb0\xaf\x91\xd5\x89\x62\x53\xc3\x97\xda\x19\x7a\x2f\xc8\x89\xf5\x66\xc3\xeb\xda\x95\xfa\x2d\xc8\x01\x39\x1d\x93\x8f\x02\x9e\x0a\xd2\x12\xa4\x4b\x29\x7c\x11\x64\x88\xb9\x6e\x8d\x42\xf0\x51\x40\x56\x7c\x85\x2f\xe1\x99\xa8\x61\x0d\xce\x3f\xff\xd8\xc9\x5c\xa8\x90\xaf\x41\x37\xc9\xc0\xfd\x05\x24\x1b\xbc\x90\x7f\x70\x8a\x9e\x99\x11\xbc\x13\xec\x2d\xbc\xa8\x1d\x67\xfe\x41\x0c\xf8\x2c\xd8\x3b\xf8\xde\xb8\x99\xe5\x5e\x6f\xa0\xbc\x5b\xf2\xd9\xcc\xf2\x0b\x81\x69\xd2\xd0\x28\xfa\x9b\x16\x5d\xd8\x48\x99\xc0\xd7\x4a\xf5\xd2\x71\xde\x0a\x1b\x8a\xff\x27\xdc\xcf\x47\x62\xa9\x32\x2e\x53\x69\x4c\x62\xb0\xd8\x9b\x2a\xa9\xa0\x01\x8d\x4e\x3d\x63\x36\x35\xec\x93\xaf\x96\x83\xd1\x04\x7e\x08\xb6\xf8\xc1\xb8\xf4\xf8\xbd\x19\xf3\x38\xc5\xfc\x8f\x58\x2f\xe3\x2b\x8c\xdd\x49\x6d\xc6\x14\x78\x23\xd8\x0f\x01\x32\x5e\xad\x9b\xa8\x86\xf2\x4c\x37\xd1\x75\xe5\x6b\xd2\x6d\x0d\xa4\x4d\xcf\xe9\xa9\x34\x4d\x27\x88\xb8\x56\x77\xc8\x98\x6f\x7a\xec\x4d\x14\x4d\x33\x95\x23\xaf\x5d\x96\x2b\x32\x97\x2b\xb9\xdc\xc1\x78\x61\x1f\xf3\x61\x05\x7d\xbc\x0c\x95\x4f\x0d\x8e\x1d\x9b\x04\x46\x9f\xc7\x4f\x52\x99\x27\x85\x69\x74\x34\x33\x86\x40\x68\xa6\x23\x8e\xff\x03\xdf\xd7\x3e\x11\xb1\xe5\x9f\xe9\x31\x12\xf0\xb8\x59\xb5\x89\xe3\x7a\x93\x6c\x4c\xde\x08\xd0\x31\x28\xe4\x09\x78\x55\x1b\x6f\xcf\x6c\x6c\x26\x10\xc6\x2c\x88\x21\x8a\x59\x18\xc3\xa8\x11\x36\x4a\xc3\x57\x3a\x93\x86\x7e\xed\x62\x54\x55\xde\x54\xd3\x9d\xd5\x56\x35\xb2\x2b\xe3\xe2\x4f\x2c\x17\xc7\x73\xf0\x9c\xdf\x32\x55\x49\x1a\xf5\xdf\xc0\x6c\xe7\xf3\xee\x9e\xd5\xd5\x6a\xf0\xf1\xe3\xb2\x9a\x9e\xa0\x3a\xc7\xff\x8f\xf9\xb3\x3d\x99\xb7\xe1\x82\x09\x4c\x70\xce\x1f\x25\x70\xdd\x34\xcd\xeb\xe8\xe1\x34\x2f\xdc\x56\x42\x61\xb8\x62\xa9\xaf\xe3\x6c\x2d\x5a\xf1\x8a\x73\x8b\x32\xcd\x87\x76\xf4\xf6\xde\xa5\xa1\xde\x43\x12\x9a\x89\xa1\x85\x52\x2d\xd2\x24\x11\x3c\xd3\x21\x35\x70\x2f\x4e\xf2\xca\x9b\x94\x5a\xcd\x43\x75\x7a\x86\xa6\x3b\x3d\x10\xac\x07\x31\x33\xa6\xad\xd9\x1d\x81\x0d\xd9\xb4\x95\xc2\x94\xec\x45\xa7\x52\xc5\x50\xf1\x55\xcc\xc6\x64\x14\x43\xf1\xcf\x53\x41\x02\x41\x81\x70\xcd\xee\xf9\x0b\x6f\x12\x43\x70\xe1\x91\x58\xb3\xfb\xe0\xc2\x9b\x09\x08\x6e\xbd\x28\x06\xff\xda\x9b\x89\x84\xba\xc1\x85\x79\x11\x6b\x37\xb8\x35\xef\x62\xed\xfa\xd7\x49\x0d\xb9\xe0\x88\xb9\x29\x2d\xf4\x73\x1c\x8c\x2a\x8d\x7c\x6d\x61\x99\xb9\x76\xf9\x8b\xcc\x37\xc3\x32\x65\xdd\x27\xad\xd8\x14\x05\x17\x60\x35\xf3\x54\x2d\xef\x61\xe6\x60\xb3\xfe\x78\x77\xb7\x54\x4d\x15\x24\xda\xa9\xd6\x02\xc1\x72\x76\xae\x17\xec\x86\x31\x19\xc6\x80\x48\x07\xb7\x4b\x14\x98\xa2\x96\xdb\x00\x02\x5d\x93\x14\x7e\x0b\x82\xfe\xb1\x3a\x23\xbc\xc4\xd5\xac\x18\x96\x86\x37\xcf\x62\xcc\x33\x0f\x13\x61\x04\x3e\x11\x9a\xfd\xcb\xf9\x17\x20\xa7\x40\xdf\xc9\x77\x41\x7a\x46\x40\x92\x1e\x35\x02\x86\x54\x54\x82\x6e\xa6\x2d\x08\x6d\xd5\x05\x1e\x83\xd0\xf0\x5a\xa0\x97\x96\xc2\x45\xcc\x48\x60\x0f\x4b\xba\x49\xdd\x7e\x3b\x24\x2f\xec\x3d\x6e\x4c\xa7\x35\xc8\xd4\xc4\x2e\x48\xea\x2d\x6e\x3a\x7b\x64\x36\xad\x6c\x86\x20\x93\x60\xe1\x2a\x09\x16\xfe\xe7\x96\x47\x00\x31\x0b\x50\x7a\xa5\xc2\xe1\x3f\x34\x3e\x96\x4c\x0e\x23\x2f\x62\xd7\x5a\x1b\xe7\x8d\x1b\x5a\x19\xdb\x78\x35\xf7\x3d\xcf\x77\xfc\x5d\xbc\xd2\x79\x6c\x6c\xdc\x18\x14\xfc\x4c\x95\xbc\x1b\x43\x4e\xe9\xbb\x31\xf9\x51\xcb\xff\x54\x4c\xd2\x33\xb1\xd8\x66\x59\xc2\x55\x2d\xd7\x2d\x44\x2e\xa6\x10\xc7\x6a\xd2\x68\x68\x06\xa3\x71\xbd\xc4\x4d\x5b\x64\x88\xfc\xa9\x6b\x61\x60\x8e\xc9\xa5\x40\x44\x2f\xd1\xec\x30\x7f\x34\x1e\xf9\xfc\x01\x21\x6c\x7c\x8c\x9a\xec\x19\xe2\x74\xdb\x34\x4b\x76\x21\xff\x66\x74\xfd\x3f\x4f\xe8\xdf\x8e\x2d\x9d\x56\xe0\x67\x38\x14\x9e\x4e\xdc\x7e\x05\xc9\xe5\x1c\x2f\x19\xf8\x69\x5c\x01\xbf\x70\xd7\x33\x0f\x38\x46\x15\xe0\x80\x9c\xca\x33\x0a\xfb\xe4\x2e\xce\x07\xbd\x78\xc3\xaf\x5a\xf1\xb6\x5c\x31\x3b\xe0\xcb\x6b\x5e\xa6\x83\xd5\xf6\x4f\x5c\x3c\x15\x30\x6e\xc9\x38\xce\x20\x50\xcc\xe3\x90\x24\x20\x1a\x97\xac\x95\x80\x4a\x97\xe9\xa0\x69\x99\xca\xa2\x8b\x97\x44\x57\xce\xc2\x79\x99\x85\xe3\x86\x7b\x45\x62\x4c\x58\xb0\x97\x39\x47\x8c\x3c\x8b\x51\x3e\xc7\x85\x5f\x04\x65\x9a\x91\xcf\x39\x98\x66\xb1\x56\x16\x67\xbc\x2a\xce\xd0\xa5\x12\xff\xa5\x1d\x7c\x43\x0e\x62\x2b\x0f\xca\x6a\x8b\x99\xa4\xc3\x98\x3d\x8b\xeb\xec\xa1\xb5\xd4\x63\x98\x7e\x8b\x0c\x7f\xa9\xd4\xd8\x82\xa3\x54\x7e\x3e\x15\xe4\xad\x4e\x0d\x2c\x12\x69\x76\xef\xf7\xbc\x13\x41\x48\x68\x7f\x3a\x89\x03\xc1\xa5\x77\x15\x43\xf0\xd4\x73\xc0\x81\xe0\xd0\x3b\x44\x29\xea\xdc\x3b\x10\xbc\xf3\xba\x09\x75\xfd\x1e\x35\x95\x42\xed\x06\x97\xa6\xde\x89\x20\xe6\xf7\x53\x6a\x6a\x9b\x5f\x87\xa6\x81\x7d\xeb\x5f\x53\xd3\xac\x86\x16\xe5\x22\x2d\x76\x17\x48\xae\xb7\x48\x59\x9b\x49\x82\x1d\xbd\xc3\x5d\x7f\x13\xc3\x7b\x41\x22\xdb\x05\x3e\x46\xd8\xf5\x0d\xd9\xcf\x4b\x7a\x34\x7d\x19\x21\xae\xf6\xad\x41\x34\x42\x30\x56\xf2\x50\x0a\x97\x8d\xb6\x42\x7a\x2a\x8c\x66\xc2\xc7\x3f\x58\x24\xaf\xfe\x60\x91\xbc\x8d\x9b\x5d\x9f\xd6\x41\x59\xf6\x4d\xfe\xac\xc5\xe9\x96\xbc\x8d\x2b\x8a\xac\xef\xd3\x04\x7e\x2f\x4b\x82\xdc\x77\x54\x93\x4c\x3f\x63\x36\xfd\x52\x4e\x44\xcd\xb2\xfc\x32\x1c\x1d\x45\x63\x8d\xf9\x51\xcb\xa7\xfb\xd9\x72\x64\xb7\x12\xca\xd5\x7f\xc7\xf6\x9e\x6e\xf9\x74\x9f\xc2\xf1\x32\x5e\x69\x5f\x24\x73\x60\xb6\x60\x88\x09\xa8\xbb\x66\xe0\x3d\x9b\xc0\x32\xff\xe4\xae\xdb\x1a\xe0\x37\x06\x7e\xc7\xa8\xf5\xb4\x28\x7e\x15\x46\xdb\x1c\x3b\x4f\x9b\x80\x8f\xc9\x71\x5c\xfd\x66\x79\x06\xe7\x85\x86\x9f\xb1\xfd\xac\xbd\x05\x84\x9f\x7b\xff\x64\xf6\xc6\x54\xc3\xd3\x98\x1c\xc5\x86\x18\x28\x9c\x34\x0b\x5e\x4b\x14\x36\x4e\x20\xa1\xf0\xbc\xa9\xe6\x3d\xdf\xf7\x30\x0e\xc1\xc6\x40\xf2\x96\x77\x8b\x21\x00\x31\xf9\x14\x53\x38\xd6\xa4\x45\x53\x0b\xed\x65\x85\x2e\x30\x46\x38\xbf\xfa\x01\x71\xf1\x51\xcd\x5a\x43\x4d\x81\x31\x9b\x20\xce\x4e\x23\x7f\xc5\x0d\x27\x36\xe9\x09\x99\x14\x37\x8e\x61\xbf\x2f\x63\x78\x1e\x57\x8e\xc9\xf0\x21\x88\xae\xae\x84\xc4\x03\x1d\x0a\xef\x63\x7b\xfe\x56\x67\xff\x90\x0b\x23\xa5\x2e\xb5\x51\xbc\x2e\x75\xfe\x1f\x6e\xcd\x37\x4b\xdd\x57\x8e\xe3\x28\x7c\xa9\x47\x32\x16\x14\x5e\xc7\x0c\xdf\x62\x8e\x66\x87\xc2\xbb\x98\x91\x91\x66\x28\xd4\x3e\x68\x18\x6a\x78\x1f\x9b\xe1\x7c\xd0\x70\xa5\xe1\x75\xf6\xfb\x5a\xc3\xaf\xec\x77\x4b\xc3\x97\xec\xf7\x44\x03\x17\xe9\xef\x99\x06\x91\xfd\xb6\x86\x55\xcd\xc0\xac\x7c\x4a\xe8\x59\xc9\x98\x54\xd5\xb3\xdf\x3a\x56\x41\x14\x4d\x60\x64\x8f\xfd\xe3\x34\xe8\xe7\xf3\x0a\x73\xec\x35\x48\x98\xda\x0f\x37\xc1\xf7\x55\xca\xd0\x7d\x30\xf2\x14\x04\xd2\x93\x10\x28\x4f\x43\xf0\x02\x33\xf0\xc1\x87\x98\xcd\x24\x7c\xad\x65\x12\x63\xf2\x21\x86\x7b\x7e\xe3\xad\xf7\x80\x6f\x79\xeb\xbd\x04\x7d\x3a\xdf\x62\xf6\xd0\xfd\x9f\x0f\xe1\x47\xcc\xae\x25\xbc\x69\xc4\xee\x80\x8c\xc9\x17\xdc\x40\x98\xcc\x9c\xd7\xf3\x46\xbf\xdd\x26\x0e\x7a\xe0\x5c\x3e\x9f\xe3\xf1\xad\xb1\x3e\xc6\xda\x1a\x2e\x1c\xad\x06\xea\x19\xc9\xcd\x57\xc7\x2e\xb4\xbc\x8d\x5e\xf9\xdc\x07\x86\x9e\x00\xe1\xa1\xc0\xd4\x4d\x6d\xc3\x11\xd9\xc0\x04\x1b\x6e\x6b\x3e\x37\x32\x3e\x7f\x23\xcc\x1b\x61\x90\x4a\x1f\x87\xf6\xc5\xb0\xf0\x87\xdf\x10\xc5\xa1\x00\x96\x66\x71\x12\xee\xb0\xef\x33\xe1\xe6\x79\x27\xb1\x5a\x17\xfd\x67\xc2\x0d\x00\x1f\x7b\xc0\x5d\x1f\xb8\x1b\x00\x77\x87\xc0\x5d\x41\xb3\xf7\x06\x9a\x8f\x7a\x5b\x76\xa0\x90\x3a\x7e\x20\x62\x46\x9b\x18\xb1\xd8\x7e\xd5\xa8\x82\xe5\x02\x4a\x01\x84\x90\x76\x6b\xb1\x8b\x28\x8c\xd2\x94\x19\x0b\x68\x99\xf2\xb4\xeb\x0c\x43\x61\x94\x16\x33\x82\x1c\x29\x4c\x24\x07\x23\x5c\x49\xc1\x6b\xe4\x4f\x4d\xc4\x5e\x0a\xdf\x54\x08\x62\x08\x62\x9a\xc7\x13\x71\xcc\x34\xe6\xdb\x6f\x58\xe3\x47\xb5\x87\x78\x12\xbd\x18\x27\x16\xd3\x45\x59\x73\x43\x34\x4f\xbd\x0c\xb7\x44\xd8\xc9\x0f\x28\x84\x8b\x7a\x26\xf6\x6d\xea\x29\xbc\x32\xb9\xa8\x02\x94\xc0\x04\x05\xa0\xd0\xb2\xbe\xb8\x6e\x7c\x16\xf5\xbc\xaa\xbd\x11\x53\xbb\x02\xd5\x65\xaf\x4e\xaa\x99\xd2\x84\x02\xe7\x8b\x61\x7c\x1b\x3d\x9b\x1d\xba\xdd\x4e\x7f\x0d\x4b\xbf\x85\x91\xb9\x59\x77\xe6\x11\x29\xd1\xfe\xe0\x85\xbd\x3d\xc4\x83\x7f\xd1\x0f\x70\x6e\x43\x9c\x5b\x1b\x2f\xe9\xe3\xdc\x56\xd1\xb2\x2a\x61\x90\x53\x09\x7e\x04\x26\x00\x85\x59\x29\xb2\x85\xef\xe2\xc2\x63\xc2\x94\x24\x4d\x34\x81\x1d\x71\xcc\x01\x10\x30\x8e\x1d\x71\xa4\x4d\x22\x18\xc7\x21\x0e\x29\x8c\x0c\xf1\x80\xcf\xf8\x9f\x36\xc1\x02\x16\xa9\xd1\x0a\x86\xce\x63\x83\x45\x54\xa1\xc0\x11\x22\x92\x1f\x0e\x42\xf0\x7f\x34\x8f\xc3\x6c\x1e\x87\xcb\xf3\x68\xa6\x01\x53\x57\xe1\x4e\xf6\x61\xc6\x0c\xd2\x13\xb3\xb7\xe1\x7a\x69\x6f\xf7\x70\x5a\x7c\x7b\x4d\x6f\x71\x46\xb5\xcd\x95\x90\xcf\x68\x9a\x21\x32\x9d\xd1\x72\xc3\x00\x3b\x0f\x59\xe0\x0e\x31\x61\x8e\x00\xbc\x71\x09\x18\xcd\x06\x33\x36\x42\x14\x46\x88\xc2\x68\x69\x66\x03\xd7\x87\xa0\x98\xd9\xd0\x2c\x8d\x1b\x40\x68\x40\x96\x76\xb2\xa1\xf9\x68\x09\x97\xf2\xac\x86\x7c\x85\x63\x2f\x9b\x3e\x6e\xa6\x8e\x9b\x69\xab\x06\x84\xda\x4b\xed\xad\x76\xdb\xfe\xe0\xe5\xb7\xc3\x74\xfe\xb3\xa7\xc2\xdc\x0c\xb8\x11\x7c\x98\xb2\xa0\x38\x43\xac\x7d\xa9\x92\xf2\xa8\x75\x85\x8b\x66\x24\x66\x70\x35\xe4\x89\xdc\x2a\xfa\x2b\x1a\x29\x79\xad\x70\x17\xf9\xb8\xfa\x41\x4e\xee\x71\x96\x1f\xbe\x70\xcd\xf0\xba\xc9\xb0\xae\x21\x9e\x1d\xbe\x60\x07\x61\x06\x3e\x62\x61\x79\xd5\x34\x87\xd0\xe5\xf9\x42\x45\x9c\x84\x66\xef\x44\xf9\x5a\x04\x71\x65\xb0\x29\x23\xe7\x78\x77\x8b\xfe\x45\x51\x10\x27\x30\x5a\x8e\xe3\xae\x89\xdb\x0d\xe2\x9a\x83\x70\x85\x99\xf1\x15\x8e\x5c\xd9\x91\xbf\xc2\x9b\x87\x7b\xdd\x62\x1e\x79\xb6\xd6\xe5\xe1\xdb\x0f\x03\xe2\xd4\x84\x66\x6a\xc2\xac\x2c\x32\x53\xa3\x8a\xa9\x89\xb2\xa9\x19\xb1\x68\x61\x6a\x22\xd7\xfc\xcf\x87\xc8\x0d\x60\x4c\x46\x86\xed\x46\xc8\x5a\x9a\xa6\xc7\x12\x69\x5a\x95\x2f\x4d\x51\x73\xf1\x98\xf8\xe6\x9d\x4f\xc2\x92\x30\x47\x6a\xc7\x23\x87\xfa\x09\xcc\x5c\x7b\xf7\x7f\x35\x6f\x87\xf6\x33\xf7\xe9\xfc\x94\xe9\xb1\xb2\x77\x90\x2d\xb5\x52\x85\xc3\xd2\x65\xb6\x2d\xd1\x46\x1a\x26\x09\xc9\xef\x30\x66\xb4\x35\xc0\xe9\xd2\x39\x1d\x71\x43\x07\x01\xa5\x5e\x79\x7e\x34\xcf\x87\x95\x4e\x41\x40\xcb\x13\x49\x61\xb6\x3c\xce\xcc\x0c\xc2\xfa\xaa\x90\x78\xda\xe0\xa8\x0b\x89\xa7\x17\x98\x61\x16\x94\x6f\x44\x8f\xb6\x12\x6f\xd2\x2c\x53\x15\x49\x4f\x1f\x74\x91\xf0\x51\x60\x22\xd6\x19\xc7\xb7\xde\x2d\x89\xcd\x2f\x81\x9f\x40\x49\x28\x5c\x57\xb7\x74\xf5\xdb\xd3\x43\x11\x44\x43\xf1\xf9\xe4\xd5\xb3\xe8\x6a\x1a\x49\xcc\x62\xd9\xf0\x15\x6a\x18\x36\x5e\x72\x38\xd2\x99\xf3\x76\x60\x35\x79\x2f\xf5\xa7\x65\x61\xdd\xad\xe6\xe9\x7a\x13\x83\xc3\x9c\x34\xdf\x9e\x36\x0a\xae\x36\x5a\x6d\xbb\xbd\x8e\x7f\x2b\xf1\x17\xa8\x0a\x5d\x73\x34\x21\xcb\x5e\xdf\xdc\xb4\x2e\x1f\x01\x5e\xf3\x52\xd2\xf7\x94\xd1\xe2\x61\xf1\x84\x03\x87\x21\xc7\x8f\x7a\x2c\x04\x1a\x5f\x35\xe0\x09\xa2\xce\x1c\xac\xf0\xf2\x3c\x45\x6c\xc6\x16\x95\xab\xf3\x10\xc2\x70\x64\xb5\x76\x6d\x14\x64\x6d\x47\x85\x59\x65\x6b\x82\x41\x8e\xb4\x0d\x07\x6e\x7a\x36\x6b\x41\xa4\x0d\xe4\x6d\x01\x11\xe9\x1c\x3e\x74\xcc\x6c\x8f\x8c\xe9\x40\x84\x99\x3f\x8c\x9f\x10\x2e\x1f\x08\xd7\xf7\x04\xa5\x60\xe6\x00\xaf\xb0\x07\xd7\xd4\x6d\x0d\xc2\xd8\xc3\x10\xdd\x16\x87\xd0\x6c\x75\x03\xa4\x6d\x3f\x08\x43\x0d\xa8\x63\x78\x6b\x2f\x9a\xc1\x05\xaf\x09\xb5\xcb\xa3\xfd\x3f\x69\x18\x93\x1f\x31\xf4\x00\x5f\x7d\x8b\xe1\x6b\x4c\x9c\x7f\xfe\x19\xa0\xd1\x29\x5d\x7e\x4c\xed\xb1\x9f\x3f\x38\x26\xa9\x3f\xdf\x06\x9d\x8e\xc9\xe7\x18\x0d\x75\xb4\x59\x2e\x35\xf5\x8e\x89\x19\xc7\xa5\xa6\x60\x86\x75\xc5\xe1\x5d\x0c\x27\x44\xc2\x3d\x3f\xf6\x2e\x35\xf0\x91\x87\x69\x17\xaf\x3d\xed\xfa\x49\x75\x03\xbc\x88\x3d\xe1\xf2\x04\xa6\x3c\xbd\x29\x74\xce\xb3\x30\xb9\x1b\xfb\x6b\x27\x81\xbb\xba\x91\x5c\xa0\xfc\x59\xca\x0f\x91\xe5\x5b\xb0\xdf\xa8\xe6\x78\x27\xa2\x7a\x6d\xdc\x98\xb3\x95\x82\xcd\xa2\xe0\x71\xa5\x60\xab\x28\x78\x52\x29\xe8\x16\x05\x3b\x95\x82\xec\x33\xba\x6b\xe7\x7c\xe1\xfb\xb5\x37\x7c\x51\x3f\x9f\xf2\x24\x81\x71\x9d\xc5\x58\xba\xa1\x75\xdb\x50\x9e\xdd\xd0\xda\x6f\x28\xcf\xfc\x6c\x07\x0d\xe5\xd9\x0d\xae\x67\x38\xc9\x9b\x09\x1c\xf2\x55\x86\xf5\x42\xb4\xa1\xb1\x3a\x8d\x15\x71\xc4\x99\x94\x70\xd9\xc8\x61\x84\xb1\xf5\x1f\x0a\x69\x2f\x67\x7c\xac\xb7\x8e\x13\x78\xc5\xd9\x11\x27\x63\x72\xc9\x61\x13\xb6\x36\x29\x85\xb7\xf8\x55\x8b\x9f\x9c\xed\x93\x43\xa3\xee\xbc\xe2\xf0\xd6\xfc\x47\xe1\x37\x67\xd7\x70\xbc\xdc\x63\xd9\xa3\x6d\x18\xd4\x6f\x0e\x5b\x9b\x20\xed\xc7\xba\x8c\xc4\x42\xde\x96\x0e\x44\x1b\x92\x4b\x3f\xb5\x2a\x8a\xcb\x20\x78\x38\xd1\x97\x4c\x80\xb2\x2e\xe8\xa7\x0d\xf6\x3c\x4f\xe0\xd3\x9f\x50\x38\xe2\x44\x3d\xdc\xda\xcc\x39\x9e\x2e\x4e\xc8\x32\xdc\x5c\xde\x97\x66\x47\x1a\xc6\xdf\xa2\xa0\x18\x86\x71\x9e\x70\xa6\x24\x3c\x6f\x9c\xd4\xee\xde\x2b\x7c\x1e\x48\xcf\x30\xbf\x97\x9c\xfd\x80\x5f\x0d\x88\x66\x21\x3c\xef\x6b\x05\xbc\xd1\xd8\x53\x6c\xb7\x36\x1f\x28\x57\x80\x60\x27\xe9\x42\x6c\x6d\x82\xde\xe8\xe1\xa7\x39\xe4\xe0\x8b\x61\x66\xe7\xd4\x53\xee\x39\xde\x90\xf9\xc4\x8d\xd5\xe9\x16\x8c\x1a\x97\xe9\x17\x27\xca\x1d\xd1\x8e\xe1\x2c\xcf\x39\xec\x80\x78\xf0\x8a\x53\x30\xac\xa3\x50\x68\xca\x35\xd3\x65\xc5\x62\x0a\x5f\x38\x1b\xc1\xeb\x26\x1f\x46\x89\x67\xab\xbd\x6e\x31\x97\xef\x39\xac\xf7\xe0\xfe\x1c\xdd\x20\xfa\xe1\xd6\xe6\xbc\x0b\x23\x2f\x4b\x44\x6e\x59\x08\x70\xef\x96\x7c\xc1\x31\x61\xac\x5c\x1a\xe1\xa7\x36\xcc\x20\xf1\xd8\x01\x89\x83\x83\xa0\xd9\xe1\xc3\xbb\xda\x09\xeb\xee\xc9\xdc\x2b\xfb\x5f\x5b\x9b\x78\xd2\xfc\xc5\x68\x1d\x72\x43\x97\x7c\xa8\x37\xe4\x35\xde\x1a\xdc\xd0\xa6\x07\x09\x2d\x10\xf9\xf8\x7f\xf2\x84\xc2\x8b\xba\xe5\x5a\x97\x6e\x2b\x81\xcf\x4d\xeb\x9e\x6d\xfa\x2c\x7e\xef\xfb\x8a\x8a\x95\x40\xbf\x0f\x2b\x2a\x56\xc2\x82\xbf\xfe\x81\x17\x7d\xe3\xec\x39\xfc\xa8\xa5\x34\xbc\x5e\xd4\xe4\x05\xee\xf4\x12\x8a\xa7\xcf\x09\xbc\xe1\xec\x1c\xe4\xe2\x77\x62\x16\xee\x67\xf5\xf6\x98\xa5\xf0\x42\xf7\x2a\x3c\xbc\x6a\xa3\x87\x24\x88\x37\x5b\x74\xbe\x5b\x41\x33\x6e\xc6\xa0\x82\xe6\x73\x5e\x19\xa0\xea\xdb\x32\xc4\xa6\x57\xd4\x7b\xc3\xf1\x70\x54\x05\xd0\x85\x1f\x46\x95\xdf\xe8\xa5\x21\x6d\x22\x60\x2f\x20\x0e\x6a\xf7\x5a\xc7\x71\x12\xe0\xc1\x7f\x10\xaa\x6f\x84\xe9\x52\xbc\xfe\x31\xf9\x44\xe4\x69\xf7\xcc\xc8\x60\xfb\xa9\x9a\x1e\x35\x12\xd6\xbe\xed\xc8\xd3\x5e\xa9\x68\x93\xa2\x04\x4e\x20\xa8\xc5\xc9\x4a\xea\x7f\xe4\xda\xda\xda\x9a\x93\xea\x0a\xff\x48\xa3\xb5\xd1\x04\xc2\x80\x1d\x4a\x88\x9a\xe6\xc1\xf9\x47\xfe\x23\x89\xd3\x89\x03\x22\x3b\x3d\xda\x71\xe8\x9a\xd3\x09\x02\x32\x0a\x52\x4f\xec\xa8\xa1\x4b\x3f\x40\x6e\x96\x80\xbf\x0c\x7a\xd5\x41\x4b\xe6\x28\x28\x6c\xd3\xd2\xd1\xa6\xbd\x53\xcd\x03\x12\xe7\xfc\x54\x96\xbf\x82\x6c\x63\x81\x8a\x34\xff\x99\xff\x8f\x8c\x04\x51\x46\x7f\xb3\xa1\x53\x8a\xd2\x76\x7b\x4c\x44\x00\x7e\x6c\xf6\x24\xc1\x94\xd0\x10\x58\x7a\x12\x03\xc7\x75\x3a\xb1\xe7\x9c\xfe\x0b\xbf\x76\xfe\xaf\x33\xc7\xde\x02\xc4\x40\xb3\x9a\xbb\x9b\xf6\x1c\xc8\xda\x3b\xce\xa9\x9d\x2b\x97\xd3\x8e\x73\xe6\xf4\x4b\x70\xc3\x55\x50\x36\xbd\x34\xce\xdb\xe5\xf6\x6e\x8a\xd5\x3b\xa3\x42\x87\x1e\x31\xa3\x49\x0e\x9c\x4f\x17\x62\xed\xf5\x2c\x92\xee\x73\xd4\xfe\xdd\x48\x8a\xe3\xd1\x1a\xd7\x6b\x97\xb3\x48\x3a\x9d\x4c\x2d\xfb\x82\x37\xa0\x3c\x67\xa9\xaa\x43\x3b\xce\xda\x88\x87\x13\xfc\xa6\xfb\x9a\xbe\x10\x6b\xa3\x68\x32\x89\x6e\xec\xb7\xa8\xe3\x80\xfc\xe0\x24\xa2\xa6\xd6\x0d\xbf\x9b\x79\x4e\x7f\x81\x8c\x0c\xe9\xe0\x80\x46\x30\x26\x3a\x80\x28\x80\xc8\xa8\x9a\x92\x71\xa6\x59\x84\xa7\x5b\x01\x53\xcb\xca\xb1\x73\xc2\xe5\x5a\x28\x75\xb4\xc6\x6b\x46\x80\x9f\xc7\x97\xd1\xda\x34\x9a\xcd\x42\x3f\x9c\x84\x3a\x14\x33\xa7\x63\x07\xdd\x3c\xbe\x75\x87\x56\x4e\xd9\x7c\x5c\xfc\x19\x2e\x49\xb6\xf8\xa8\xbe\x3a\xef\x55\xe4\x4f\xc4\x95\xed\xc8\x0c\x1b\xd3\xef\x34\x41\xee\x38\x9e\x19\x2a\xee\x19\x6f\xb9\xed\x79\x78\x2d\xa4\x85\x80\xf5\x1c\xda\x21\x41\x40\xc6\x24\x0c\x60\x1b\x66\xa6\x7d\xfa\xda\x37\xfc\x68\x16\xb0\xa9\x84\x49\xc0\x66\x01\x79\xa9\x29\x5c\x07\x6c\x28\x61\x58\xc7\x01\xf3\xd9\x9e\x04\x30\x26\xd7\x01\x94\xae\x65\x37\xd7\xbf\xe7\x53\x4f\x03\xff\x61\xd8\xf8\xc8\xf2\xf1\xab\x80\x5d\x49\xb8\x08\xd8\x8d\x84\x69\xdd\x2e\x2d\xe9\x87\xe7\x0d\xe5\x4f\x20\xc0\xf2\x9b\xa6\xf6\x3b\x70\x8e\x15\xee\x1a\x2a\x64\x07\xb9\xe3\xc0\x88\xe0\x9d\x04\x6e\x2b\x63\xa8\x7e\x16\x67\x4c\xae\x82\x9a\xf0\xaa\x31\xb9\x08\x20\x86\xa5\x48\xd9\xbb\x80\x04\xd5\xd8\x22\xac\x79\x13\x90\x03\x72\xca\xe1\xdc\x14\x9f\x19\xf3\xa5\x62\x6a\x4c\x91\x79\xe1\x17\xfc\xbd\x3b\xfb\xc3\xa0\x87\x91\x22\xc1\xaa\x10\x1b\x5c\x91\x5b\x72\x9b\x2f\xcb\x38\xa0\xb8\x04\xf6\xda\xff\xc1\xaa\xc5\xf9\xea\x69\xf0\x63\x4f\x81\x9f\x5e\x32\x7d\x16\xa4\x86\xce\xa1\xe1\x0e\x0b\xc3\xae\x1e\xf7\x3b\xb1\x9c\xaa\x28\x10\xb3\x99\x18\x3a\x5e\x31\xf6\xae\x3d\x08\xc8\xee\xcf\x95\x4a\x7a\x69\xc9\x2c\x9e\x4e\xd5\x52\xbb\xcd\xa5\x23\x82\x69\x40\x9c\xcf\x72\x2c\xa3\x1b\xb9\xa6\xef\xa6\xc2\x5b\x73\x3a\x18\x38\xf1\x2c\xa0\x70\xd4\xb0\xb2\x8f\xc0\xb7\x17\xf6\x03\x76\x4b\x86\x01\x14\x17\xfb\x9e\xde\x39\x70\x14\x10\xd3\xd8\x96\x64\x57\x00\x97\x0b\x34\xd7\xc2\x81\xc3\x00\xee\x02\x72\x10\xe0\x09\xea\xc7\x80\x45\x0d\x2e\x59\xfc\x24\x50\x3e\xa7\xbf\x0c\xc1\x1f\x78\x21\xf0\xd7\x5e\x0c\xfc\xbd\xa7\x52\xfa\xbf\xf0\x04\xf8\x37\x1e\x07\xff\xce\x8b\xc0\x7f\xee\x61\x38\xe4\xab\x0c\x4f\xc9\xaf\x84\x03\xcf\xb0\xcf\x9a\x91\xf1\x6d\x5c\x21\x0a\x6f\x03\x36\x8d\xe1\x67\xc0\xde\x0b\xf8\x5d\x2b\xe5\x7e\x9a\x0d\x9f\x85\xd8\x3e\xb6\x21\xb6\x34\x81\xe3\x80\x69\x09\x4f\x83\x45\x67\xac\xfd\x2a\x66\x96\xaa\xf5\xe1\xe9\x3f\xb3\x5b\x3f\x3a\x7b\xe8\x6a\x31\x43\xc7\x4d\xee\x22\x48\xb3\x4d\x75\x64\x91\x6d\x81\x59\x35\xc1\x8a\xf9\x4f\x01\x7b\x16\xc3\x49\x2d\x4e\xf8\x19\xf3\x9e\xd5\xd5\xea\xe3\x94\x2b\x91\x7f\x46\x88\xdb\xee\x12\x78\x6e\x48\xf1\x6d\x95\x14\xc3\x11\x79\xb2\xf7\x42\x94\xd0\x3b\x09\x88\x73\x70\x3b\x15\x81\x16\x43\xc3\x3c\xaf\xa2\x99\x5e\x7b\xb2\x36\x0c\xcf\x43\x3d\x83\x35\x3f\xd6\x6b\xe7\x91\xb6\x92\xc4\x36\xa4\xe9\x78\x9e\x06\xc4\xe9\xba\x86\xb4\xf2\x71\xb9\xad\xc1\x49\x40\xfe\xf5\x4a\x5e\xf3\x49\x38\x5c\x1b\x4d\x22\xae\xbd\x35\xe7\x5f\x1d\xd9\xf9\x97\xf3\x2f\xea\x3d\x15\xe4\x38\x20\x3d\xb1\xf5\xc0\x3a\xa3\xe0\x9b\x20\x9f\x02\x12\x61\x40\xe5\xcb\x80\xbd\xd5\xf0\x2b\x60\x7f\xf8\x88\xd7\x4b\xa3\xbb\xec\x76\x1f\xa8\x07\xbb\xdd\x07\x3d\xb1\x65\x7e\x13\xbd\xc1\x29\x3e\x18\xe0\xa2\x13\x9b\x2d\xfc\x3e\x68\xf8\xb2\x40\x17\x75\x8a\x8a\xfa\x06\x82\x6d\x6f\x61\xb6\xee\xed\x1d\xc6\xf4\xa0\xe7\x75\x21\x66\xa2\x1f\x17\x19\xf8\x3a\x9d\x22\xe5\x6c\xb9\x71\x9c\xe6\xf8\xdc\x7e\x3c\x9f\xef\x3c\xda\xe3\xa5\x85\x57\xac\xd7\x7d\xa0\x3a\x7c\x63\xfb\x71\x9e\xbe\x13\x3f\xdc\x82\x31\x35\xb6\xa7\x0d\xe5\x29\x9a\xc0\x97\x12\xb2\x65\xb1\xb1\xbc\x80\x36\x10\xd4\xf0\xc1\x8c\xa3\xbe\x0f\x48\xf3\x22\x84\x52\x8b\x73\xa1\x16\x96\x41\x95\xb2\x6d\x54\x48\x00\x17\x5a\x1b\x75\x61\x15\x09\x54\x56\x2e\x81\xd7\xb5\xb4\x6b\xe0\x66\x58\x0c\xf9\x9d\x67\x21\xa0\x9a\xfa\x2e\x60\x6f\xe0\x45\x5d\xab\xf5\x31\x79\x67\x64\xae\xa4\xed\x36\xc1\xdf\xbd\xae\xb1\x32\xe6\xf3\xb4\x04\x9f\x68\x02\x9f\x6b\x95\xf2\x8d\x2c\xf9\x3f\x51\x0f\xb7\xe7\x5d\xba\x41\xd4\xc3\x5e\xb7\x3b\xef\xd2\x8e\x79\x83\xbf\x12\xf8\x5e\xb3\x35\xb2\x98\x1e\x5e\x3e\x11\xb3\x2b\x9b\x1b\xa6\xaf\x03\xc2\x33\xf2\x5f\xee\x7c\xab\xb7\xb3\xb5\x2b\x76\x1f\x10\xb1\xd1\x7b\xf2\xa8\x4b\x41\xb3\xc7\xbb\xdb\x62\xe7\x01\x21\xf1\xde\xd6\x7c\xbe\xfe\x22\x20\x82\x0e\xf8\x46\xcf\xe3\xb4\x43\x3e\x9b\xa7\x8d\xcf\x01\xc1\xca\x85\x03\xed\xa9\x20\xb2\xa3\x3a\x9a\x26\x99\x1f\x2c\xce\xbf\xdd\x9a\x56\xd9\xea\xed\xf1\x01\x22\xe3\xa9\x4c\x70\x14\xf9\x42\x37\x9f\xec\xf1\xf9\x7c\xf3\x09\x63\x8c\xb7\xdb\x69\xaf\x59\xed\xcd\xdd\x47\x8f\xb7\xc5\x0e\x5d\xc8\x54\x5a\x81\xb8\xd3\x7d\xf2\x68\x37\xaf\x93\xe7\x3a\xdd\xea\x96\xea\x3c\x7a\xf4\x68\x57\xec\x2e\xe6\x6e\xac\x80\xe9\x75\xb7\x76\x1f\xe7\x75\x76\x6b\xc1\xf4\xb6\xba\xdb\xbb\x05\x3e\x8f\xea\x01\xed\xec\x6e\x95\x90\x7e\x5c\x5f\xe9\xf1\x56\x6f\xf7\x71\x5e\xe9\x49\x6d\x77\x9b\xdd\x27\x4f\x76\x36\xf3\x4a\xbd\x6e\x2d\xa8\xcd\xad\x9d\xc7\x8f\x4a\xb5\x7a\xf5\xb0\x76\x37\x77\x77\x8a\x69\xea\x6d\xd6\xc3\x7a\xfc\x78\xc7\x4e\xe6\x82\x94\x2e\xef\xd1\xab\x48\xea\x0b\xdc\xa1\xb1\x31\x86\x70\x97\x1a\x2d\x6b\x29\xde\xbf\x51\xbf\x7c\x4a\xb2\x8f\x34\xa6\xa1\x8d\x5f\x02\xb2\x4d\xe1\x77\x40\x9c\x0d\x87\x96\x5e\x6e\x96\x5f\xe2\x33\xa5\xf0\x61\x85\xe6\x2a\x1f\x10\xc3\x6c\x3b\xa8\xb2\x7e\xad\xd9\x38\x69\xbd\xec\x82\x5c\x05\xe5\xf2\x3f\x36\x0e\xfe\x17\x72\x00\xc4\xe1\x93\xb3\x8c\x97\x57\x87\xac\x57\x42\x16\x2a\xfd\x58\x98\x6f\xb5\xad\xe7\x62\x0e\x82\x80\xda\x78\xfb\x33\x5a\xaa\xfd\xa6\x2e\xa6\xb6\x9b\x60\xb3\x1f\x16\x8f\xc5\xb9\xfe\x10\xfc\xa1\x79\xcf\x36\xef\xd8\xe6\x75\x55\x36\xd2\x2a\x66\xb6\xcf\xfe\x30\xb0\xa2\xfc\xa9\x20\x13\xf2\xcb\xa8\xa4\xdd\xec\xff\x6d\x98\x26\x5e\xee\xfb\x1e\x50\xf8\xd6\x60\xa5\x3f\x8d\xe1\x6b\x60\x6f\xaf\xd5\xe8\xa1\x96\x4b\x7d\x5b\x14\x16\xd3\x0a\x9b\xd6\xa9\xba\x68\x94\x69\x14\x12\xa8\x35\xbe\xa9\xed\x70\x95\x7f\xc8\x9e\x7c\xb9\xf6\xde\x11\xba\x59\xc2\x18\x31\x93\x61\x83\xed\xb1\x99\x6a\xa0\x2a\x64\x17\x12\x74\x5d\xb5\x35\xfc\x46\xe1\x9b\x00\x64\x68\xe5\x88\xa8\xad\x65\x4d\x86\xf3\x80\x5c\x62\xa0\xaf\x0a\xe1\x48\xdb\xc8\xfb\x04\xe2\x90\x15\xca\x6a\x3c\x73\xe0\x32\x48\xb5\x57\x21\x87\xb3\x7d\xed\xc0\x8f\xec\x45\x3c\x35\xd3\x31\xac\xbc\x9b\x69\xae\x74\xb5\xda\x28\x94\xe7\x42\x4d\x55\x28\x35\xea\xa1\xf6\x6d\x96\x37\x63\x86\x3a\xf2\xab\x5c\x47\xe6\x52\x46\x1a\x13\x62\xce\x1c\xd0\x21\x6a\xcf\xfb\x64\x3f\x00\xe7\x5c\x48\xa1\xb8\x8e\xd4\xe7\x93\xb7\x0e\x08\x5b\x74\xa9\xd3\x76\x13\xee\x8b\x49\xd1\xe4\x2e\x20\x1f\x03\x9a\xff\x1f\xf0\x6c\x58\x69\xfe\x0f\xd3\x69\x1c\xd2\x05\x64\x1c\x78\x15\x34\xc2\x6b\x59\x85\x3d\xa8\x9b\x52\xeb\xc5\x0c\xc3\x55\x31\xa1\x1f\x63\x24\x18\xef\x55\x5c\xca\x21\x15\x35\x35\xc9\x4e\x2b\x32\x37\xe5\xa8\x81\x2c\xb2\x23\x11\xbf\xa1\x3c\xb3\x48\x67\x61\x7a\xe4\x31\x09\xd3\xe0\xc3\xeb\x5a\xda\x48\x9d\x4c\x09\x0c\x1b\x01\xfa\x9e\xa3\xc5\xad\x76\xb2\x74\x78\x21\x3b\x97\x70\x15\x1a\xed\xf4\x22\x5c\x7d\x8f\xe4\x2a\x24\xf7\xfe\x07\x63\xb0\x6c\x7b\x84\xb3\x18\x86\x21\xa9\xb3\x80\x5b\xa1\xbd\x91\xf7\xa1\x72\x28\x9a\xce\xe2\x28\xfd\x7e\xb6\x99\x49\x1b\x63\x4b\x21\x08\x3c\x05\xc1\xd4\x93\x10\xbc\xf1\x2e\x35\x04\xef\x3d\x0d\xc1\x89\xb7\xde\xcb\x7c\xe2\x09\x85\x69\x98\x26\x73\x38\x6f\x5c\xa8\x1b\x72\x11\x82\xf3\xe2\xe0\x93\x03\x2d\x90\x30\x0d\xed\xde\xbc\x09\x6d\x00\x70\x2b\x24\x68\x0d\x3b\x42\xa9\x48\x19\x72\xa6\x36\x1c\xf8\xae\x61\xb6\x32\x2f\xf2\xf8\x0f\xcb\x77\x1b\xae\x90\x30\x44\xa5\x49\xfe\xf6\x43\x76\x2c\xe1\x20\x64\x6f\x25\x3c\x0b\xd9\x41\x68\x34\xf3\xc3\xb0\x29\xa9\xe6\x98\xec\x87\xb5\x11\xac\x21\xb1\xf7\x36\x6d\xe6\xa8\xa3\x4a\xdf\xf6\xda\x4c\x3d\x08\xf5\x37\xa0\xc7\x24\x4d\xa9\x96\x80\xc8\xba\xb8\x0c\xd9\x57\x09\x1f\x97\xa7\x3d\x75\x67\x64\xab\xfc\x5c\x12\x84\x7c\x19\xa6\x1a\xbc\xb1\x64\x17\xa7\xa6\x84\xc4\x61\x58\x2f\xb6\x48\x9a\xdc\xe9\x63\x68\xd3\x64\xd9\x04\x4f\x47\x21\x19\x6b\x0a\x07\x21\x69\x21\xf0\x22\x57\xd2\xdb\x4a\x1f\xe5\xd1\x74\x0d\x0a\x3f\x1b\xe9\x05\x51\xb0\x97\xa8\xfa\xdf\xa5\xfb\x89\xcf\xc6\xec\xde\xf7\x9e\x85\x10\x78\xaf\x42\x18\x7a\x6f\x43\x10\xde\xcf\x10\x46\x9e\xaf\xad\xe9\xf9\x3b\x84\xe3\x10\x9e\x86\xec\x9b\x24\x8e\x69\xe0\x50\xf8\x14\xb2\xa7\x12\x4e\x1a\xbb\x79\x6a\xa6\xf5\x53\x68\xcc\xd8\xf4\x9f\x83\x10\x24\x85\x8f\x18\xc5\xbc\xbf\x5c\xf0\x2a\xa6\x36\x81\x19\x85\xe7\x2b\x90\x3f\x09\xd1\xe9\xff\xc2\x10\xdc\x25\x4e\x77\x5d\xb2\x8e\x94\x27\x0c\xee\xaa\x9b\x75\xc9\x9d\x9d\xe9\x81\x4e\x9a\x88\x79\x4d\xdc\x06\x42\x0c\xc5\xd0\xa9\x6a\xe0\xce\x91\xd0\x37\x91\x1a\xaf\xd9\x5d\xb4\xa0\x6a\xe3\xc9\x7c\x1c\x10\x82\xc1\x09\xd4\xf5\xef\x5c\xff\x2b\xc5\xcf\xc1\x2a\xf3\x10\x44\x70\x13\xda\x34\xd4\xb9\x06\x9e\x1d\x39\x64\x4e\x50\xe7\xb3\x14\x99\xc5\xa6\xc4\x6c\x1a\xc9\x99\x58\x1b\xa9\xe8\x6a\x8d\x4f\x43\x14\xe0\xee\xe2\xc9\xb4\xf3\x8e\x4f\x46\x91\xba\x12\xc3\xb5\x58\x4d\xd2\x3a\x49\x82\xbe\x6d\xea\x8d\x43\x7b\xc5\x83\xc2\xcb\x5a\xb6\x29\x07\x8e\x56\xb1\x70\xbc\x34\x75\x5f\x02\xbf\xea\xeb\xb9\xad\xf9\x3c\x0b\x8a\x1e\x48\xf4\x6f\xbc\xaf\xad\x29\x64\x4d\xb4\x4b\x02\x5f\x6a\x2b\x67\xe9\x03\xdf\x87\xf0\x8d\x13\xd9\x71\x98\x63\x0d\xcf\xf0\x7f\x27\xc1\x9c\xe9\x69\x90\x45\xc5\x50\x3c\x6f\x4d\x93\xcc\xbd\x6b\x18\x94\x9f\xc0\x8b\xb0\xf6\x10\xc8\x3f\x2c\x3e\x9a\x18\x8c\x3b\x24\xbb\xf0\x80\xb1\x18\x4f\x39\x7c\x34\x98\xbf\x0e\xed\x0d\xd1\x77\x21\x48\x41\xa4\xfb\x8d\x52\x7b\x8b\xd4\xaa\xfa\x1d\x65\xfe\x24\xf0\xb9\x8e\x49\xa6\x76\x29\x51\x15\xb7\xa7\xb6\x51\x3d\x79\x60\xd1\xf7\xc6\x4d\x80\x13\xf1\x19\xf9\x44\x2b\x4d\xe1\xd0\x58\xf7\x98\x64\x69\x1b\x1a\x06\x3b\x42\xcf\xc9\x7b\x0c\x31\x3c\x46\x43\xf9\xc8\x1a\xca\xaf\x31\xc6\xf0\x2b\x84\xcb\xe7\x3b\x9f\xe2\x7c\x52\x38\x45\x5f\x89\x5c\x4c\xd5\xb5\x70\xe7\xf6\x85\xb6\xd3\xf5\x22\x9d\xb6\x23\x0d\x1f\xc2\xca\xf5\x09\x85\xa7\x3c\x11\x1b\x93\xef\xb5\x6c\x7a\x4c\xbe\x84\x99\xf6\x49\x13\x78\x49\x42\xb0\xc9\xa3\xf2\xf4\x65\x70\xa4\xc9\xcb\xd0\x62\xb6\xde\x03\x9b\xf0\xec\xb8\x9c\xcf\x6c\xa1\x86\xc8\x6a\xa4\x0e\xda\x4a\x71\xd7\xde\xe2\x33\xc5\x85\xae\xf5\x2b\xc4\xdc\x1d\xc7\x59\xe6\x35\x40\xff\x75\xbe\x8c\xdd\x3d\x3c\x99\x19\x38\x83\xec\xb0\xa2\xed\x40\x44\x3d\xc7\x49\xe0\x5b\x93\x24\xb1\x15\x1f\x3a\x78\x8b\xb0\xd0\xf6\x6c\x0f\x33\xa7\xf3\xd5\xf4\x79\x56\x74\xf2\xdc\x60\x78\x1e\x82\x36\x0a\x21\x0f\x2d\xc7\xfc\xf1\x9f\x41\x5f\x0d\x34\x4e\x81\xbe\xf9\x83\x82\x26\xa3\x06\x0d\x22\xab\xa0\xa2\x65\x9a\xb3\xa7\x86\x23\xa4\x37\x6e\x63\x5a\x8f\x91\xe0\x8e\x90\xde\x82\xd7\xf8\x21\x85\xaf\x7f\x4f\x09\xab\xa9\x40\xba\xef\xff\x48\x07\xf1\x6a\x3a\xe0\x59\x71\x4a\xad\x86\x0a\x82\x1a\xca\xd0\x15\xca\x08\xf1\x61\x31\x23\x1f\x51\x4c\x00\x7a\x8a\x2d\xf3\xc5\xb8\xac\xf2\x42\xac\x22\x21\x1d\xfd\xef\xb0\x46\x8c\xc8\xc3\xdc\x9b\xb8\xf3\x0c\xdf\x45\x67\xb6\x7d\x3c\xd6\xc4\xc6\x14\x52\x38\xd2\x94\x96\xed\x3a\x0a\x22\x4a\xb5\xcf\x38\x4a\x35\x70\xde\xb0\xe4\xd9\x31\x55\xd0\x50\x9e\x51\x44\xd8\x50\x9e\x85\x39\x45\x0d\xe5\x59\xa2\xea\x51\x43\x79\x6e\x53\x44\xec\x48\xc2\x2c\x62\x42\x11\x67\x2a\xd4\x2c\x9c\x69\x9c\xfd\x83\xdb\x29\x97\xc3\xfd\xc9\xc4\x01\x3f\xa2\x30\x89\x9a\x18\xe6\x09\x51\x70\xcf\x5b\x5e\x1e\x80\x77\x12\xc3\xa7\x18\x0c\x65\xa6\x69\x43\xae\xeb\x70\x30\x12\x65\xe0\xdc\x67\x8b\x06\x78\x8e\xff\x02\x19\x9e\xa4\xb4\xe3\x24\x0e\x2e\x61\x0b\x27\x72\x3b\x81\xab\x08\x8d\x8f\xa8\x36\xfe\x56\x32\x33\x96\x69\x23\x8e\xa8\x5b\xa5\x5a\x1c\x66\xd2\xae\x82\x69\xbe\x1d\xb9\x7c\x1d\x75\xc1\xcf\xb8\xe8\xd2\xda\x4a\x12\xb8\x89\xd8\x77\xb8\x8b\xd8\x57\x18\x37\x62\x24\xf7\x7a\x03\xc7\xc9\x52\x05\xa5\x22\xe7\x36\x62\x9f\x61\x3f\xfa\x83\xf7\xff\x9e\x1f\x7b\x1c\xf8\x67\x4f\x01\x1f\x19\x3b\x8b\x7b\x1a\x7c\x61\xec\xa2\x6b\x7b\x5f\xea\x20\x6a\xbe\x2f\xf5\x52\x90\x98\xce\xe7\x63\x72\x1b\x81\xf3\xff\x71\xcc\x5e\xae\x9e\xd2\x70\x36\x26\x77\x11\x38\x9e\x93\x26\xfc\xe0\xe9\xc9\x3d\xc7\x93\xfb\x6a\xe5\x2c\xb5\xef\xfb\x80\x8c\xc9\x77\x01\x41\x07\xb9\x43\x16\xca\x10\x2e\x25\x97\x8e\x58\x98\xed\xdc\x23\x4d\x26\x64\x3f\x42\xed\x74\x1c\xd9\xaf\xd1\x45\xe9\x09\x65\x39\xda\x34\xad\x14\xc3\xa5\xce\x4b\x29\x3c\x8b\x9a\xf2\x11\xbf\x14\x44\x2c\x0e\x2a\x4e\x07\xf5\xd0\x81\x2c\x7b\x8f\x5f\x93\x9c\xe1\x86\x1c\x58\x7c\xbe\x0b\x1b\x34\xa5\xf0\xc6\xfa\x38\xc2\xa7\x52\x48\x3a\x56\xc3\x18\x57\xfb\xad\x57\x0a\x87\x51\xfd\xbd\xaa\x97\xc2\xf0\xb9\x2a\x36\x22\xc5\x66\xe0\xa4\x57\x91\xaa\x29\x94\x8b\xd8\xb3\x67\xa6\x1b\x8c\x4c\xfd\x2e\x20\xee\xa0\x8c\xc6\x34\x07\xe3\x08\x62\xb4\x9d\xaa\x55\xed\x0c\xa1\xc1\xb7\x4c\x79\x16\x19\xb5\x88\x8c\x4e\x91\xf9\x1f\x4e\x1a\x38\x58\xc9\x31\x57\xca\x4d\x71\x58\x46\x46\x74\x7a\x66\x2f\x59\x54\x44\x39\x61\x72\x5a\xd1\xa0\x82\x66\x61\xed\xe6\x1f\x93\x9b\x08\x9c\x0b\xad\xa7\xde\xc3\x87\x0e\xa0\x2e\x7a\x14\x41\xd7\x4e\xfd\x23\xc3\x02\xbc\xa2\xce\xac\x52\xa9\x67\x2b\x3d\xc6\x4a\x46\xb9\xfe\x18\x31\xad\x89\x33\x8a\x02\xbc\x2c\xfa\x2a\x62\x3f\x14\xbc\x8d\xd8\x0f\x09\x3f\xeb\x56\xc5\x8e\x0d\xf9\x56\xf0\xda\x3b\xd2\xe4\x3a\x22\xda\xe5\x2d\x5a\x4a\x85\x7f\x4c\x4e\x88\x46\xbe\xd6\x32\xb6\x63\x64\x7d\xa0\xaf\x22\xd0\x6e\x30\x86\x97\x06\x54\x44\x84\xf5\x57\x9e\x84\x70\x28\x48\x2b\xa2\xf0\x31\xca\x84\xde\x86\xcf\xd5\xc6\x15\xd7\xc1\x05\xaa\x6b\x69\xe2\x86\xdf\xcb\xab\x52\x4e\xdf\xad\xf2\xfd\x95\x46\xfe\x60\x98\x32\xaa\x8b\xd6\x1d\x92\x16\x76\xd3\x38\x3f\x8c\xaa\x3c\x8e\x9a\x7d\x03\xbf\xa3\xfa\x34\x2a\xc8\x6f\xac\xc8\x7a\x1a\xb1\xb7\x91\x31\x96\x3f\xd5\x6f\xa8\x94\x37\xea\x65\xde\x78\x4b\x7e\x46\x18\x77\x76\x42\x04\xdc\xf3\x9f\x9e\x76\xb9\xe1\x69\xc2\xe5\x3f\xc1\x0a\x84\x28\xbd\x2a\x28\xcc\xec\x0e\xcc\xbf\xde\x4b\x62\xfe\x18\x25\x24\xc6\x54\x0e\xb4\x7c\xff\x3c\x2e\xe7\x1c\xae\x85\xff\x22\x24\x31\x2d\x75\xf1\x3a\x84\x43\x4d\x62\x6a\xbb\xc8\xc1\xe5\x96\xa6\x59\xc7\xbc\x35\x0e\x77\xf1\xa8\x28\xab\xa1\x4a\x35\x16\x98\xfa\x31\x11\xe6\x35\xc6\xb0\xae\x96\x83\xfe\x63\x6f\xe1\xa8\xb2\x1a\xd1\xb5\x76\x40\x4e\xad\x4e\x89\x67\xf6\x67\xb4\x4e\xf7\xcf\x4c\xa5\x17\x02\xde\xd9\x24\x7b\x36\xc2\x0d\x1c\xdc\x67\x44\xba\x5f\xad\x60\x7d\x8e\xc2\xf1\x71\x02\x2f\xeb\x36\xd9\x3a\xda\x6c\xbf\x1a\x77\x00\xc4\x76\x0f\x7c\xf5\x08\x46\x96\x3d\x86\x97\x86\xa4\x51\xd7\x72\xa8\x77\x48\x04\x2c\x62\x4b\xd3\x63\xdb\x54\x66\x3b\x68\x11\x94\x37\x8d\x6e\xda\x2a\x71\x79\xab\x3c\x4f\xb7\x0a\x6a\x7e\x1b\xfe\xdd\xc6\x28\x14\x93\x61\xb1\x4d\xde\x37\x4e\x32\xc6\x30\xfe\xc9\x72\x4b\xff\x7c\x59\x86\x52\xb9\x21\x81\x31\xaf\x18\x7f\x63\x6f\x3f\x6c\xf4\x40\xe1\x7e\x5b\xbe\x03\xa1\x8a\x1f\x09\x85\xd7\x75\x53\xda\x0c\x3a\xbd\x28\x83\x31\xd1\x79\x27\xa0\xd3\xd0\x3c\x23\x01\x96\x3b\xd4\xc5\x0f\x63\x92\x37\xce\xc7\x17\x4d\x6e\xc9\xeb\x28\x0d\xff\xc4\x8b\xe7\x0d\x72\xa8\xbb\x97\x7f\x26\xe4\xd8\x7e\x3a\xb2\xc0\x58\x95\x71\x5f\x17\x65\x39\xaf\xfb\xf9\xab\x54\x0d\xe8\xd9\x6b\x1c\x34\xbd\xda\xd7\xb7\x7f\x55\x92\x32\x0a\x53\x94\xb9\x8a\xb2\x2a\xa5\x78\xc0\x18\xbf\x0e\x50\x6c\x86\xd8\xc5\x64\x47\x2e\x3f\x2b\x7f\x0a\x3e\xed\xaf\x90\xd1\xc2\xf5\xed\x85\xd5\x52\x53\xa3\x79\x04\xf8\x3f\x6c\x9e\xde\x35\x54\xf9\xe6\x2d\xc3\x69\xb7\xf3\x9f\x19\xd0\x10\x81\x46\x2c\x74\x7d\x18\xb1\xc8\xf5\xf3\x9b\x9a\xbe\xcb\x61\xc2\xfc\xf2\x37\x08\xc6\x1a\x6f\xfb\xe1\x8f\x28\xfb\x31\xca\x7e\xcc\xa0\x27\xb6\xf6\xe4\x60\x4c\xde\x45\xa0\x36\xb6\x61\x42\xbd\x5b\xf2\x22\x02\x69\xa4\x24\x3e\xe3\x77\x08\xb2\xa9\x5a\x5a\xe5\x03\x72\x2a\xd2\x51\x64\x4e\x81\x84\xc2\xe7\x15\xdb\xe0\x45\x54\xa8\x8d\xdf\x9b\x85\x9c\xae\xe3\x2b\xd6\x05\x63\xc4\xbc\xd9\x92\x9f\x23\x10\x1d\xa3\xf3\x7c\x89\x40\x6c\x20\x81\xda\x5d\xf8\x61\xb9\xfb\x85\xeb\x72\x19\xe8\x1f\xdc\x3a\x78\x6a\xfd\x25\x69\xa5\xf5\x43\x62\xd3\xe3\xb5\xdb\x86\xb3\x58\xf9\x83\x7e\x96\x88\xbd\x87\x6f\xb5\x5a\xc2\x2d\xf9\x1a\x15\x5f\xa0\xf8\xd1\x38\x1d\xf6\x1e\x0f\x7e\xb6\xc0\xda\xe1\xb5\xca\xcf\x61\x25\xf4\x3a\x15\xb0\x20\x98\xcd\xec\x19\x5b\x6f\xf2\x8f\x88\x84\x98\x1e\xe2\x7d\x64\x23\xa5\x7b\x46\x0d\xfc\x16\xd9\x0c\xa7\x9c\xd9\xb8\x93\x80\x11\xbc\x09\x60\xb4\xc2\x87\x9b\xf3\x2e\xdd\xe8\x41\xc8\x30\x2f\xc4\x98\x7c\x4f\x75\xd9\x26\x78\x1c\xe1\xd9\xe4\x54\x11\xfb\xc1\x49\x48\x0d\x01\x3e\xe4\xe0\xb3\xe8\xa1\x80\x19\xcb\x5c\xdb\xb8\x5a\x1f\x0c\xf3\x4c\x33\xd3\x73\x78\xc9\x89\xbb\x63\x5a\xe2\xc1\xd6\x7b\x0d\xbf\x34\x7e\x69\x22\xe7\xc1\xd1\xa0\xf7\x70\xeb\x01\x19\x75\xfc\x0e\x89\x36\x66\xf4\x61\x44\xbd\xae\x61\x8a\xa3\x15\xb1\xe9\x19\x5f\x90\xc5\xdd\x11\xee\xfa\xf3\xf9\x22\x2f\xb8\x2e\x7d\xe5\xa3\x9c\xd8\x32\xdf\x49\x59\x72\xa4\xd0\x68\x2b\xf7\x92\x05\xa0\x58\x04\x9a\xbd\x24\xda\x08\x13\x6e\x44\x7e\xf6\xb5\x73\xb4\xdc\x75\x29\x16\xde\x2a\x35\xa6\xba\xc6\xaf\xc2\xa8\x51\x1d\x51\x4c\x89\xa4\xee\x65\x14\x4a\x82\xd9\xcb\xf5\xa8\x29\xce\x3b\xcb\x7f\x64\xfe\x2a\xa3\x98\x1c\xe6\xb7\x4b\x46\xe4\x96\xc8\x91\x5d\x06\xbb\xb8\x29\xf7\x14\x75\xb3\x84\xb7\xe5\xca\xc0\x68\x6e\x1d\xd6\x90\x55\x36\x9c\x8e\xbb\xb9\xf3\xe0\x85\x20\x63\xa2\x47\xd6\xf0\x7c\x40\x7a\x1b\xa8\x9c\xc7\x7f\x89\x73\x37\x43\xb9\xe7\xdd\x12\x81\x50\x8c\x2a\x10\xe5\x76\x2c\x1f\xb1\x3b\x08\x46\x7f\xa7\xb8\x3d\x2a\xab\x33\x25\x31\x2d\x4a\x62\xda\x1a\xf3\x81\x55\x85\xfe\x5a\x64\xf7\x17\x15\xc3\x5f\x65\xc5\xed\x65\x49\x31\x7c\x09\xfe\x63\x54\x01\xfd\xc7\xa8\x02\x1a\xbd\xe3\xcc\x6c\xac\xae\xd1\xb3\x57\xe9\x82\x35\x20\xe3\x1c\x62\x45\x0f\xf4\x1f\x2f\xc0\x5b\x52\xf5\x7a\x8b\xca\xe0\xf6\x62\x8d\xb7\x78\xb1\x8f\xf7\xf0\x1b\x14\x45\xbd\x9d\x85\x7a\xfe\x78\x11\xd2\x92\xe2\xa9\x16\x6b\xec\x96\x6b\x70\x96\x0d\xc8\x0c\x97\xe3\xd7\x11\xbb\xde\x4b\x41\xb8\xcb\x5f\xd2\x81\xd1\x70\x8d\x9d\xbe\xe6\x80\x7d\xc1\x5d\xde\xf5\x90\x67\xf7\xba\xf0\xc5\x28\x62\x7c\x04\xf1\xc8\x56\x87\x82\xc5\xd7\x9a\x5c\xc7\x66\x0a\xb9\x99\x9f\x04\x9e\x0b\x0a\xcf\x34\xe1\x6e\x70\x95\x9e\x9e\x97\xc6\xda\xa0\xfe\x66\x67\xac\xd1\x88\xbd\x91\x30\x1a\xb1\xa6\xae\x32\xe7\xa8\xec\x38\x0f\x97\x82\x00\x28\x4d\x20\x1a\xd5\xc5\xa9\xe6\x5e\x2f\x4a\xc1\x1f\xa5\x69\x4f\x67\x4d\x7b\x05\xc3\x5a\x21\xb8\xb1\x67\xe7\x93\x11\x9b\x48\xd2\x7b\xd8\xa5\x70\x5d\xcb\x36\xc6\x64\x36\x32\xf2\x67\x1b\xec\xa1\xd3\x36\x6a\x60\xc5\x05\xd1\x87\xa7\x1b\xa7\xff\xfc\x73\x76\x9f\x10\xfa\xa0\x33\x70\xe1\x9f\x7f\xfe\xf9\xe7\x7f\xb6\xe6\xff\xe3\x9f\x7f\x66\x67\x0f\xcf\x1d\x6a\xd8\xed\x64\x04\xba\x71\x7e\xa5\x1b\xc8\x04\xbe\x71\xe2\xfc\xf3\x8f\x43\xed\xd1\x5c\x76\x7d\x23\x81\xe1\x5f\x6e\xd2\x6e\x31\xe9\x5b\x98\x90\x85\xbb\xad\x81\xa5\xb5\x0b\x0f\x85\xc2\xf5\x08\xcc\x5b\x4e\x13\xea\x89\x15\xf6\xcc\x4b\xcf\x71\x00\xa9\x65\x6c\x0c\xd9\x6d\xcf\x41\x67\x5e\x70\x83\x7e\xb5\x8c\x86\x84\xeb\x5f\x98\xe9\x9e\x7a\x97\x1a\x7c\x65\xbf\x4e\x99\x6d\x7a\x7f\x64\x37\x7d\xb6\x86\xf9\xa6\xff\xeb\xed\x50\x6c\x65\xde\x5f\xc2\x2f\xfe\x33\x7a\x19\x89\x37\x4f\x3a\xdf\x4e\xcc\x06\x88\x29\x4d\xc7\x42\x69\xe3\x6e\x33\x28\x2a\x8c\x17\x68\xde\xfa\xfe\x74\x79\x4b\x5b\x1d\x74\x79\x0c\xfe\xd8\x5b\xef\x41\x06\xb2\x9e\x99\xfa\x23\x0f\xb9\x39\x4f\x4d\x27\x8c\x65\xa0\xcb\x19\x13\x4b\x36\x66\xab\x89\xe4\xd3\x88\x22\xe8\x5a\xbd\xef\xaa\x96\xd0\x51\x2b\x68\x8d\x20\xb2\xb1\x46\x17\x8d\xc0\xd2\x2b\xfa\x08\x6a\x3a\x5a\x95\xf6\x12\x53\x21\xf0\x8f\x10\x9a\x3f\x53\xcc\x88\xc2\x5f\x01\x5e\x42\x39\x07\xdf\x3c\x45\x30\x63\x71\xc7\xf9\x1f\x0f\xd3\xf3\x92\x7e\xe3\xc1\x31\xce\x9d\x11\x32\x91\x4d\x77\x5c\xcc\xb3\xbd\x29\x35\xc1\xf8\xd3\xeb\xf2\x19\x5a\x0a\x6b\x92\xc3\xb2\x2b\x22\xd9\x04\x6f\xe6\x9c\x90\x00\xee\x83\x2b\xef\x6a\x64\x93\xbb\x3d\x35\x5a\xf9\xb7\x55\x1b\x95\xff\x48\xe0\x40\x53\xfb\x4d\x38\x0a\xa9\xb6\xb5\x4a\x7b\x5d\xbb\x25\xad\x00\xde\xd8\x6b\x50\x96\x5c\x63\x7b\xbd\xc0\x49\x50\x97\x3d\x30\x84\xaa\xa3\x3f\x74\x8a\xa5\x07\x1a\x5e\x87\x75\x67\xf0\x96\x43\x5b\x8b\xe6\x31\x92\x09\x62\x58\x10\xdd\x38\x24\x9a\xe6\x5f\x0b\x2f\xb1\x0a\x11\x41\xb0\x98\x44\xe9\x98\xc4\xf8\x76\x89\xce\xee\x42\x32\x71\x6d\x0e\x8d\x84\x54\x1c\x5e\x76\x59\xae\x8d\xe4\x9b\x7a\x13\xe0\x1f\xbd\x6b\xd7\xaf\x3a\x4d\xcc\xc4\x0c\xd9\x98\x9c\x44\xa0\x21\xa0\xd0\x62\x63\x32\x31\xbf\xa3\x25\x48\x63\x2f\x8a\x81\x4f\xf0\xa2\x7c\x64\x36\x55\x30\xf0\xbd\x38\x32\xb0\xf1\x21\x8e\xbc\x10\xf8\x2b\xaf\x65\x3a\x1a\xe6\x5e\x36\x2c\x1b\x93\x28\xdd\xf4\x41\x04\x6f\x42\x4c\x09\x1a\xa2\xb1\x4c\xbd\xa2\x8c\x67\x65\xdf\xd2\x32\x28\xca\x46\xb6\x6c\x34\x22\xa2\xac\xa4\x94\xf8\x81\xb2\x3b\x56\xd9\x1d\x3b\xb3\x3b\x56\xc3\xfd\xfb\x3c\xd9\xa3\xdd\xa8\x8b\xca\x53\x53\xbb\xe3\xba\x76\xbd\xee\x02\xdd\xfb\x4f\x17\xe9\xde\x86\x36\x5c\xb1\x7d\xf2\x29\x82\x99\x4d\x22\x0e\x11\x85\x0b\x76\x55\xd0\x5f\x36\xa9\xaf\xbc\x16\xbb\x72\x39\xf8\x4f\x3d\xcb\xa9\xb3\xf1\x86\x76\xbc\x17\x05\x6f\x36\x50\xa7\x6c\x9f\x04\xa3\x1c\x6a\x40\xfb\x17\x6c\xba\x0c\xf5\xa3\x37\x64\x53\xc4\xaa\x00\x18\x2d\x00\xb4\x9b\xee\x9c\xed\x93\x61\x01\x70\x64\x00\x9e\x2f\x01\xf4\xcf\xbd\xf3\x05\x70\xa3\x05\x70\x8f\x17\xf9\xc1\x64\x71\x5e\x9e\x60\x87\x37\x65\xdf\x58\x41\x5a\x98\xef\xfa\x06\x94\xcb\xc7\x74\x30\x26\x17\xa3\xec\xc1\x1b\x93\x56\xfe\x00\xfe\x96\xe5\xcd\xb3\x88\xac\xf7\x68\xf5\x5e\xdd\x5d\x3d\x64\x23\x76\x09\x67\xc7\xc4\x87\x3b\x4a\x5d\x4c\x91\xc3\x5d\x7f\x80\xec\x25\xbb\x3a\xcb\x51\x02\x53\x8a\xd9\xc5\xb7\xbc\xbb\x9c\x7a\x67\x11\xb9\x43\x6b\x2d\x02\x19\xc1\x41\x48\xee\x52\xaf\x56\x42\xe1\xbc\x8e\x5f\x97\xce\xea\x6e\x1a\x55\x9d\x96\xb7\x5b\xf9\xcc\x51\x2d\xe3\x3f\x92\x64\x75\x34\xea\x47\x59\x8d\x46\xbd\xb7\x26\x38\x8c\x47\xec\x48\xc2\x6d\x2d\xd0\xbb\x11\xb1\xe7\xc5\xf6\x8e\xd1\x78\x64\x28\x7c\xdb\x1e\xdc\xe2\x5d\xc1\xf4\x9d\x7f\x98\x9e\x19\xcf\x4e\xc4\xb9\xb8\x75\xc0\x8f\x4c\xcd\xef\xe9\xe7\x38\xf6\x1b\xa5\xd0\x09\x27\xf2\x21\xa2\x73\x50\x8b\x80\x4c\xe0\xd9\x2a\xd3\x75\xf1\xb3\x97\x1d\xb9\x98\xa8\xce\xa6\x3e\x12\xae\x7f\x8d\x49\x7e\x8b\x9a\xc2\x26\x2f\x05\xc5\x14\x68\x7b\x3b\xfe\x70\x19\xcf\x22\x2f\x6a\x3e\x91\xcf\x50\x93\x84\x31\xd9\x1f\xc1\xc1\xc8\x58\x8f\xbb\x62\x3b\xbd\xd1\x78\x34\xaa\x4d\x4e\xb2\x6f\xac\xb7\xde\xf6\x76\x97\x76\x1e\xf5\x9e\x6c\xef\x3e\x06\xcd\x88\xda\xeb\x0e\xd4\x46\x6f\x7b\xb7\xfb\x64\xd7\x53\xf4\x21\xfe\x7a\x34\xef\x82\x60\xe9\xeb\x47\x0f\x34\xc4\x8c\x88\x0d\x22\xb0\x14\x2f\x71\x88\x87\x5b\xbb\x3b\x9b\xf6\x6a\x87\x7d\xfd\x64\x77\xde\xa5\xd4\xbc\x9e\x77\x81\x33\xb1\x41\xb6\x76\x77\x1e\xc4\x1d\x12\xa7\x37\x40\xe2\xf4\x06\x08\xba\x2e\x76\x1e\xf0\xce\x26\x7d\xd8\xdb\xd9\x9a\x77\x21\x64\x41\x87\x04\x7b\xbd\xee\x60\xcb\xdb\x78\x92\x31\xf1\x7b\xfe\xdc\xe3\x1b\x84\xf4\x76\xb6\x1e\x04\xa6\xf2\x8e\xe9\xb9\x07\x7c\xd3\x0b\xc1\x7f\xed\xc5\x9d\xed\x6e\xf7\x81\xee\x90\xcd\xbd\x70\xd0\xf5\x7a\x34\x49\xe0\xb2\x71\x8d\x8f\xcc\xd6\x39\x4c\xad\x60\x97\x3f\x4f\x28\x7c\x5c\xa1\x96\xbc\x0b\x60\x73\xdb\xce\x6e\xde\x0c\x76\xbb\x36\x52\x70\x75\xbb\x9e\xd8\xb2\x2b\x82\x5f\xc7\x5d\x5d\x77\xb7\x5b\x80\xc7\x08\xc0\xe5\xea\xa9\xe6\xb1\x80\xff\xe6\xa2\x4a\xd3\x5d\x50\xc1\x7b\x0b\xb6\xe0\xe6\xe2\x2d\x92\x05\xf5\x79\x7b\x41\x36\xed\x2c\xc8\x9c\xdd\x05\x96\xf9\x68\xe1\x7e\xc7\xe3\x45\x59\xf3\x64\xf1\xd6\x46\xaf\xbb\xa8\x07\xf4\x7a\x86\xde\x7f\xff\xc5\x14\xe5\x44\xde\x13\x5b\x38\x51\xc7\x7f\xb9\xd0\xfe\x6b\xc3\xce\x57\x30\xb5\x4a\x36\x87\x4f\xc6\x9e\x7c\x3a\x82\x2e\xb4\x28\x9c\xd4\x6d\xf9\x6c\xb6\xf7\xe4\xe0\x96\x9c\x8c\x40\xfe\xfb\xdf\x3d\x78\x49\x94\x21\x8f\x5e\x5b\x0e\x5e\x12\x0d\x8a\x7a\x9a\x7a\xc6\x90\x7d\xbe\x42\x8b\x3e\xb1\xbe\x14\xc7\xc1\x68\xbf\x15\x7d\xbd\x24\x63\xf2\x7c\x04\x72\xe3\x85\x30\xaa\x97\xfd\xd2\x91\xdd\xe8\xbf\x56\xc0\x7f\x69\xe0\x3b\x5d\x07\xe2\x2c\xa9\xc0\xfb\x06\xa3\xf4\xd7\x08\x0c\xa9\x1f\x8f\xe0\xd3\xc8\x06\x3e\x6c\x38\x1d\x7c\xbd\xb9\xe2\x02\x6d\xa1\xfb\xf5\x16\xb4\xbe\xcd\x05\x52\xdc\x5a\x20\xc5\xed\x05\x52\xdc\x59\x20\xc5\xdd\x05\x52\x7c\xb4\x40\x8a\x8f\x17\x48\xf1\xc9\x02\x29\xf6\xba\x8b\xb4\xd8\x5b\x4a\xe1\xdd\xdb\x4c\x12\x32\x26\x3f\xb3\x31\x57\x06\x3d\x26\x97\xc5\x5c\x7c\x2a\xbd\xfe\x58\xbc\xf6\x4a\xaf\xdf\xd6\xbf\xfe\x5d\xbc\x76\xd3\xd7\x5b\xff\x5f\xf2\xbe\x44\xb9\x6d\x1c\x6d\xf0\x55\x14\x8e\x76\x06\xdc\x7c\x62\xe4\x5c\x9d\x30\xcd\x52\xf9\x90\x63\x27\x8e\x9d\xc4\xb9\x7b\xf2\xa7\x00\x92\x92\x68\x51\xa4\x42\x82\x94\xed\x44\xfb\x1a\xfb\x40\xfb\x62\x5b\xf8\x00\xf0\x10\x49\xd9\x99\xee\xf9\x77\xaa\xb6\xba\x2b\x16\x49\x10\x00\x81\xef\xc6\x77\x08\xb9\xad\xbc\xfd\xc5\x58\xc3\x07\x01\x73\x97\x01\xcc\x27\xf0\x7a\x62\xc2\x8b\x6e\xc0\x56\xbc\x95\x70\x27\xea\x4c\x07\x62\x2d\xb3\x74\x46\x2e\x22\x82\xee\x42\x26\x24\x6b\xd3\x84\x3f\xbe\x0a\x5c\x28\xbc\x90\x5f\x4d\x9c\xe3\x08\x9e\x6f\x81\x9d\x57\x1c\x72\x57\xa6\x73\x31\xe1\xbd\x98\xe0\xf3\x09\x1e\xc4\x29\x8f\xad\xe3\x03\xe3\xab\x89\x11\x29\x9f\xb7\x00\xae\x74\x72\x7f\x7d\x76\xae\xbc\xdc\x95\x5b\xc0\x9b\x2d\xd8\x58\x4f\x99\xd2\xc1\x08\x85\x56\xb8\xe9\x23\x57\x24\x6f\x46\x4b\x9e\x43\xb8\x53\x48\x0d\xea\x04\x3c\x35\x60\x4e\x5e\x4c\xe0\x72\x02\xc4\x77\x12\x13\x0f\xdb\x85\xb8\x50\xc6\x92\x7c\xc0\xd3\x9a\x95\xbc\xad\xe3\x50\xf0\x26\x1d\xcb\x9b\x6e\xe2\x53\x15\x8b\x3d\xc7\xfb\xfb\xea\xbe\xca\x56\xad\xee\xee\x2a\x41\xc4\x33\x64\x02\xb0\x57\x13\x95\x14\x6c\x02\xbe\x45\x3f\x60\x0d\x5d\xcc\xff\x3c\x01\x83\x2e\x97\x61\xe0\x62\x28\xca\x3d\x4c\x99\x00\x98\xee\x60\x28\x3d\xc7\x4b\x6b\xd6\x25\xf9\x3c\xc1\x80\xed\xf7\x32\x89\xee\xa7\x89\xe3\x76\x46\x74\x97\x06\xaa\x5d\x3b\x03\xba\x6f\xfb\x40\xc7\x36\x07\xfa\xc1\xa6\x40\xfb\x62\x8d\x57\x76\x02\xec\xca\x76\x81\x1d\xd8\x58\xde\xe9\x4b\xf7\x56\xfe\xa0\x9f\xc5\xcb\x0f\xc5\x7b\x87\x72\x73\x5e\xa2\x71\xec\xc1\x1a\x22\xa6\x23\xd5\xb5\xd8\xf5\x72\xa2\x82\x5b\x94\x70\x56\x04\xe3\x54\x63\xc4\xbf\x4c\x64\xb9\x05\xfd\x76\x47\x94\x0f\xc6\x06\xd5\xc2\xda\x6f\x8a\xeb\xf7\x2f\x97\x41\xf2\xab\x31\xfd\x4b\x3f\xf2\x82\x68\xfa\x27\x02\xfa\xdb\xc3\xde\x55\x62\x02\x1d\x00\x24\x00\xa2\x58\x8d\x02\x66\xca\x3b\x25\x74\xed\x77\x86\x43\xb5\x84\x3e\x95\x10\x7e\xea\x92\x88\xe1\x64\x3e\x4d\xca\xa8\x24\xce\x3a\x0f\xe7\xda\xd1\xc8\x80\xa4\xe2\xde\x88\x0a\x14\x07\x6d\x51\xf5\x21\x61\xd2\x68\xe1\xb3\x0e\xc7\xc2\xa7\x4a\x9b\xc8\x5a\x1b\xb8\x73\x1b\x8d\x9f\x9f\xc4\x9f\xcf\xa3\xfb\xf6\x50\x40\x95\x90\xdf\xd7\x6b\xa0\xcc\xf9\x41\x5d\xfb\xce\x0e\x7c\x44\x73\xe0\x44\xfc\x7b\x2a\xfe\xc1\x74\x77\xaf\x31\xea\xe6\x85\xcc\xcb\xd3\xd6\x7b\xef\x2d\xa1\x0c\x7e\x9c\x0a\x45\xf8\xce\xd0\x84\x33\xfd\xe3\xb5\xfe\x51\xf8\xdb\xa0\xc5\x25\x63\xca\x04\xb3\x86\xa0\xe3\x73\xb4\x9f\x62\xcc\xb6\x67\x71\xfb\xad\x2d\x8b\xdb\x84\xa9\x80\x28\xd6\xd1\xbb\x5e\xab\xb4\xe3\xf9\x13\xf5\x3c\x64\x5d\xf4\xfa\xc8\x25\x28\x1c\xdd\x3d\x93\x61\xdd\x26\xe4\x4c\x15\xe9\x5d\x19\xf0\x78\xf8\xf0\x89\xff\x08\xe9\x91\x67\x00\x46\x42\xe3\xc5\xcc\x80\x07\x8f\xd5\xef\x85\x21\xb5\x07\x41\x0d\x0d\x94\xb1\xbe\x9a\xe0\xb5\x2e\x6f\x64\xf1\x24\x58\x10\x73\x0d\xfd\xf6\xe7\xbf\x0f\x95\x95\xd1\x63\xed\xba\xa0\x56\x66\x28\xba\x13\xcb\x7c\xa7\x14\xf3\x9d\x56\x54\x78\x7a\xcf\xff\x39\x1c\x09\xed\xc1\x95\xbf\xcd\xbb\x84\xdf\x35\x7a\x86\x69\xda\x19\xa0\x60\xe8\x83\x8c\x6d\x3b\x23\x86\x01\xf2\xd3\x21\x67\xa6\xcc\x68\xb0\x60\xce\xeb\x09\xcc\x98\xf2\x85\x5d\xb6\x2e\xee\x37\x7b\xc6\x10\xf4\xd6\x6b\x98\x0a\xb8\xdb\xb5\x97\x8c\x18\x86\x29\x28\xa6\xfa\x75\x55\xdc\x1a\x17\xbf\x3e\xa0\x3d\xa9\x6f\xf7\x05\x15\x95\x37\xd7\xb0\x12\x1d\x7c\xc6\x4c\xf7\x0f\x75\x4b\x76\x58\x3c\xbe\x62\xed\xc9\xab\xe6\xe8\x5b\xfd\x49\xae\xc5\x61\x89\x72\xef\x5a\x4d\x78\x97\xe4\xcb\x04\x12\x90\xa5\x11\x9b\xe6\x49\xbe\x29\x9a\x09\x90\xdf\xd9\xb4\xce\x4b\x3c\xd8\xa4\x6e\x98\x43\x13\x55\xf1\xf6\x99\x16\x93\x13\x5f\x29\x10\x57\x7d\x27\xea\xe2\xea\x4b\xb1\x78\xce\xe5\x36\x34\xe9\xbd\x25\x53\x06\x6a\xa5\xb9\x5e\xe8\x48\xad\xb3\x0e\x50\xe8\x33\x82\x81\xdf\xa6\x5e\xf6\x85\x78\x16\x32\x10\x77\xd1\xe1\x47\x2c\xff\x51\x4c\x12\x59\x0f\x9e\x61\x7a\xd5\xcf\xea\xe0\xe9\x8a\xa1\xc3\x34\xc3\x03\x10\xb5\x45\x0b\x86\x75\x96\x30\xba\xad\x13\x91\x10\x8b\x06\xe3\x89\xcc\xa8\x38\x46\x24\xc2\x15\x37\x0c\xf1\xff\x1d\xac\x68\xbd\x2f\x01\xc5\x30\xc4\xdc\xc5\xbf\x63\xfb\x48\xb0\x98\x12\x2c\xc6\x4c\x0c\x8a\x37\xd7\x70\xd8\x39\x9a\x0a\x33\x8c\x36\xa3\x0c\xe1\xb4\x0d\x58\xe5\xb1\xac\x78\xc1\x38\x9f\xc5\x59\xe8\xf5\xa2\x98\xf7\x98\xdf\xf3\x17\x4b\x7e\x65\x88\xef\x3f\x64\x70\xe8\x13\xe3\x63\x12\x47\xd3\xde\xf1\xf9\xd9\x93\xc7\xc3\x9d\xde\x24\x4e\x16\x94\x1b\x26\x7c\x52\x39\x1f\x2e\x5a\xd1\xf6\xc8\x17\xf8\x1a\x99\xe6\x96\x11\x8e\x33\x0c\x0d\x3a\x6f\xe3\x26\xcd\x5a\x65\x2a\x0e\xf5\x59\xe9\x7a\xa4\x45\x6f\x99\xe4\x5f\x0c\xc4\x55\xa0\xea\x9c\x44\xe0\xcb\x34\xab\x42\xbf\x6e\x02\x20\xd2\x8b\xcf\xa0\x4e\xcd\x36\x71\xe5\x9c\xc1\x9c\xc3\xa5\xf8\xdb\x29\xd2\x7e\x99\x94\x12\xe8\x05\x93\xe9\x63\xe1\x38\x13\x02\xdf\x21\x9e\x07\x9e\x34\x37\x4a\x8e\x7c\x46\x4e\x11\x42\x4f\x05\x7c\x2b\xef\x54\x2a\x13\x18\xb3\xf2\x73\xb9\x4a\x56\xa6\x92\xf2\x96\xa1\x01\xc7\x82\x38\xcb\xd3\x32\xa1\xc3\xfa\x6a\x89\xf7\x69\xf4\x0f\x5c\x5d\x95\x2d\x6c\x49\x53\x2e\xd7\x18\x5d\x79\xbf\xb1\x4e\x0f\xec\xed\x4b\x8d\xc7\x24\x45\x5a\xcc\x5a\x1b\xae\xdb\x04\x78\x8e\x54\xf8\x51\x55\xdb\xf8\xba\x4d\x8c\x5e\xc0\xcd\x84\xc2\xe7\x19\xc9\x74\x9b\x49\xd5\x6f\x59\xe5\xf2\x16\x1f\x47\xd5\xb6\xae\x48\xa4\xeb\x3e\x00\x55\x9b\x7b\xdd\xdc\x5c\x2c\x5a\xfc\x41\x6e\xee\xae\xcc\x33\xd7\x97\xa1\x26\xfb\x32\x09\xc8\x0a\xa3\x4c\xe8\x58\x0f\x75\x91\x91\x90\x7c\x63\xb0\x35\x06\xf8\x2d\xd9\x97\x84\x26\x12\x88\x8a\x49\x8d\xb2\x42\xfe\x4d\x04\x86\xfa\xeb\x1a\x30\xa0\xda\x73\xcc\x04\x50\x60\xdc\xa6\x78\x82\xd0\x21\x76\x3e\xc3\x1f\x73\x72\xc2\x40\xfc\x04\x57\x83\xcd\x19\x53\x29\xb8\xf6\x98\x33\x89\xe0\x1d\x73\x58\x04\x6f\xbb\x90\x1e\xcb\x2b\x59\xf4\xfa\x2e\x89\x06\x58\x68\xd6\xb5\x13\xac\xf2\x95\xc8\xc2\xe9\xc0\x16\x76\x22\xab\x9f\x27\x16\xe6\x5c\x3c\x60\x4e\x1c\xc1\x11\x73\xdc\x08\xbe\x37\xbb\x0d\x26\xe4\x92\x1c\x31\xd8\x19\xee\xa0\xc5\xe3\xe7\x4f\xbc\x7c\xfc\x54\xda\x3f\x34\xf2\x60\x5d\x30\x7c\xf2\xf0\x01\x96\x53\x52\xed\x1e\x3e\xc2\xab\x11\xbf\xbb\x63\x73\xd4\xaa\x0e\x98\xac\x9f\xa4\x56\xf1\x90\x88\x35\x1d\x0d\x32\x3b\x2b\x13\xfc\x9b\xf0\xba\x93\xaa\xc9\x6e\x1f\xe3\xf0\xa3\x39\xf9\xce\x00\xfb\x44\x2f\x34\x41\x8f\x6d\xbc\xa7\xdd\x23\xd9\xd6\x4a\x77\x3e\xba\xf7\xf8\xd2\x7c\xda\x56\x0a\xf1\xce\x50\x66\x5c\xca\x64\x56\x6d\x05\xdc\x15\x5a\x73\x48\x38\xe8\x6a\xa8\xb2\xc6\x1a\x37\x7f\x2f\x5e\x8a\x2a\xf5\x28\x03\xe2\xe2\xa1\x33\x03\x8a\xa5\x53\x4c\x78\xb1\x95\x8f\xd5\xcb\xf1\x57\x82\x02\x5e\x75\x63\xae\x2e\xc7\x42\xd1\x51\xeb\x35\x03\x17\xd1\x42\x7c\x5d\x50\x4d\xbb\x2a\xbf\x6c\x97\xbc\x60\x40\x11\x18\x2c\x7a\x3d\x20\xc1\x5d\x2c\x97\x1e\x01\xb5\x5c\x53\x97\x80\xb3\x18\x04\xed\xd5\x40\x29\x24\xba\x95\x5b\x69\xb3\x22\x1f\xc4\xf2\xcb\xba\x07\x62\x56\x55\x3a\xf0\xa3\x6d\x71\x29\x5a\xe8\x0b\x9a\x00\x13\x67\xcf\x25\x18\x34\x82\xa3\x4b\xcc\xae\x52\x81\x09\xe6\x5e\xdf\xec\xa1\x58\xe9\x98\x4c\x04\x2d\xc4\xb5\x0e\x94\x0c\xf7\x9c\x39\x73\xd2\x95\xe7\xd8\xf9\x41\x53\x5b\xd0\x38\x13\xe8\x73\x81\xce\x2f\x05\x71\x39\x11\xd2\xc3\x3b\x7d\xff\x93\xb8\x75\x4e\x4d\x70\x03\x3b\x01\xfa\x48\xde\x5f\x6f\x26\x6d\x92\xd0\xf9\xa4\x28\xa9\x5a\x11\x6f\xb0\x80\x5e\x72\x77\xe7\x59\x15\x90\x77\xee\x0f\xb1\xf8\x1d\x35\x47\xb8\x70\xbe\xe5\x06\x42\x85\x7f\x87\x4e\x18\xef\x98\x2a\xb7\x0b\x91\xf8\x3c\xd1\x7e\x67\xa7\xb5\xbd\x40\xb3\x4b\xb2\xc7\xe0\xc9\xe6\x1b\x4f\x9f\xb4\xbe\x90\xea\x17\xee\x57\x5e\x08\xc9\xab\xb2\xc5\x73\xf1\xcf\x27\xf1\xcf\x4b\x38\x23\x09\x0c\xb1\x8a\x97\x9a\x7c\x67\x4b\xec\x73\x67\x58\x2c\x00\x66\xec\x45\xbe\x25\x24\x69\x06\x67\xcc\x84\xf7\xcc\xa9\x65\x60\x39\xa2\x62\x83\xfe\x95\x52\xad\xd7\xd2\xf4\x28\xc4\x72\xd3\x84\xcf\xac\x59\xfa\x4f\xfd\x43\x33\x18\xb6\xc5\xff\x57\xb2\xcc\xec\xb5\xd5\x5e\xef\x2d\x30\x4b\x13\x56\xf2\x14\x3d\xbd\x67\x70\x98\x99\xa6\xaa\x0d\x9f\xe8\x8a\x9a\x87\x99\xaa\xaf\xf7\x86\x15\x15\xd6\x3e\x33\x13\x0e\x19\x29\x25\x26\x2f\x4b\xd0\x0a\x53\x88\x4c\xa6\x09\x1f\x99\x8a\xa1\xfb\xd4\x49\xf0\xf0\xcc\xee\x9b\x4d\xb8\x13\x29\x46\x22\x84\x1b\x95\x93\x81\x5b\x74\x6d\x7f\x64\xe6\xba\xb4\xbe\x7d\xf9\x05\xf1\x7a\x4e\x3e\x31\xb8\xc0\x9d\x92\x32\x76\xb2\x5e\xc3\xcb\xf6\x0e\xe8\x07\xc9\x3a\xf7\xa5\x78\xb4\x42\xd6\x49\xc7\x18\xa6\x79\x25\x19\x68\xff\x59\x69\x15\xaa\x74\xbd\x8b\x62\xb8\xbe\xc1\x85\x2c\x8e\x17\x6f\x18\x50\x14\xc0\xf1\xea\x44\x73\xc3\x0c\x45\xdd\x44\xc6\x3e\x3c\xe7\xf0\x85\x81\x8b\x62\x36\x36\x3b\x65\x58\xda\x1d\xa2\xb4\x1a\xce\x77\x20\x75\x8d\xfd\xc4\xa7\x3c\x4e\x0c\x98\x4f\x4c\x48\xd2\x1b\x96\x54\x2b\x67\xe8\x1f\x91\xd6\x93\x47\xf8\xb5\x18\x13\xee\x76\x09\x7e\xe8\xf1\x6b\x8e\x04\x2c\x60\x80\xb9\x0c\x91\xdc\x18\x99\x6f\x0b\xbf\xd3\x31\x38\x47\x18\x9f\x03\x4a\xdd\x10\x3b\x5a\x71\x47\xf0\x9d\x53\x46\x50\x8e\x31\x21\x13\xbf\xb9\x45\xc7\xb8\x5a\x49\x33\x12\x1b\x05\xd5\x5d\x26\x2b\x7e\xd5\xe3\xb0\xb9\x75\x25\x20\x41\xee\x69\x1f\x95\xab\x5a\x92\x20\xf9\x1c\x65\x83\xd2\x6d\x02\x67\x28\xf6\x2c\x49\x05\xb7\xb1\xae\xd4\x6e\x24\x29\x50\xe0\x16\x5b\x15\x93\xd5\x6e\x44\x02\x5f\x7d\x39\x4d\xb6\x92\x9b\x8a\x1f\xf0\xff\x6a\xba\x08\x63\x6a\xba\x74\x5c\x4c\xf7\xa1\x4d\x95\x9d\xa0\x32\x55\x25\xe5\xbe\xc1\xe9\x06\x0e\xc9\xe5\x04\x43\xc1\x4d\x7d\xd3\xc4\x51\x71\xed\xed\x05\x23\x79\x65\x42\xd5\x71\x69\x7d\xdc\xa0\x3e\xee\x23\x7b\xf3\x15\x89\x0d\xe5\x3b\x12\x1f\x8a\xd5\xc3\xb7\xab\x28\x50\x5b\xf5\xc7\x75\x50\xda\x97\x63\x62\x32\x66\x8b\xee\x17\xcd\x7e\x6b\x36\x53\x18\x59\x6d\xf5\xa4\xde\x6a\xb7\xd6\xd9\x6e\xd1\xec\x69\xb3\x59\xd1\x59\xd9\x6a\xa7\x09\xe4\xe8\xf5\x96\x3a\xaa\xc3\xbe\x29\x9d\xf2\x53\xc1\x1d\x75\x78\x9a\x3e\x5c\xd1\xb9\x95\x19\x4c\x9c\x4b\xc2\x53\xf5\x5a\xab\x4d\x2e\x42\x87\x25\x9c\x6b\x2c\xc9\xd9\xda\x5c\xcb\x2e\x9f\x6d\xcc\x61\xb2\x2e\x13\xbe\xdd\xbe\xe3\x0a\xa1\xbc\x45\xcf\xf7\x8b\xac\xc6\xec\xd9\xad\xc6\x60\x87\x72\xf2\x58\x05\xf7\xf0\x36\x43\x3c\xb8\xdd\xe4\xb5\xe5\x73\x5b\x87\x55\x8f\x91\x14\xc2\xdb\xcf\x9a\x7e\xb6\xc3\x6d\x3d\xa3\x54\x97\xaf\x4d\xc8\x52\x87\x5c\x07\xce\x91\x0b\xd7\x51\x8d\xcd\x46\xe4\x24\x22\xd7\x01\x39\xa0\xdc\xb7\xa2\x78\x45\xa4\x73\xa3\x09\x34\xdd\xe6\x4c\x5a\xf5\xb9\x93\xde\x97\xd7\x42\xcd\xa2\xa7\x2a\xf0\xb5\xa0\x20\xda\xe7\xe5\xd4\x7e\xa9\x1a\x00\xe3\xf6\x55\x40\x8c\xfd\xc2\x04\x91\x66\x6c\x11\x70\x95\x53\x3b\x59\x40\xef\x5c\x5a\xa9\x7b\x41\x8a\xcf\xaf\x7c\xde\xc3\xbc\x69\x96\xa1\xfd\x2e\x1b\x51\xb5\xda\x29\x88\xdb\x59\x5c\x09\xa6\xd4\x9e\x41\x8c\xc1\x1c\x65\xd2\x8f\x13\x69\x57\x84\x28\x15\x6a\xec\xbe\xf2\xa3\xf1\x19\x8c\x03\x79\xa3\xe2\xc8\x25\xbd\x83\x5c\x07\xdd\x75\x62\x99\x46\x46\x88\xbe\xda\x33\x8b\xdf\x35\xfe\x76\x4f\x9f\x4c\xdd\x33\xee\xc6\x42\x2f\xde\x8b\x9b\x73\x12\x53\x72\x0b\x6a\x21\xb5\x98\xa8\x6a\x0e\x4d\xe4\x34\x70\xae\x97\x24\x46\x40\x87\x40\xf0\xa3\x00\xf9\xb7\x98\x7c\x96\xb6\x38\x8a\xfd\xa0\x17\x68\x95\x5a\xda\x7e\x0c\xf4\xd4\xde\x25\x97\xac\xf0\xc0\x89\x2c\x17\x22\xcb\x33\xc1\x9d\xdb\x38\x61\xc6\x6d\x3f\x5e\x57\x7d\xcd\x11\xc7\xab\xf3\xb8\x24\x5c\xb0\x02\xfc\x5a\x39\x9f\x14\xd7\xae\xe1\x53\xf5\x00\x83\x0e\xa9\xd5\x1f\x95\x7b\x4c\x98\x83\x14\x1d\x73\x89\x33\x21\xb2\x84\xe2\xcf\x3e\xe4\x0e\x13\x22\x8b\x27\xae\xc6\xd0\x17\x7f\xfa\xda\x4a\xc8\xb4\x84\xb2\x64\x24\x6c\x1a\x0a\xe7\x64\x97\x41\x0e\x9e\x59\xb3\x16\x7a\x26\x4a\x29\xa7\x9c\xa4\x66\x21\xa9\xcc\x19\xf4\x2b\x06\xc1\x5c\x19\x04\x71\x69\x4f\xb8\xd8\xe1\x39\x25\x13\x21\xab\x9a\xb6\xf8\xd6\x0d\x9f\xc3\x49\x0d\x88\x27\x4d\x20\x5e\x4a\xc0\xa5\x11\x82\xa5\x17\xa4\xcb\x90\x5e\xf5\xe8\x64\x22\x33\x04\xed\xa2\x5f\xea\x56\xf0\x85\x0a\x22\x28\x50\xa6\xce\xa4\xe9\x22\xb6\x94\x60\x5c\x71\xbd\xd3\x00\x8c\x2e\x8a\x2e\x13\xb0\xda\x2f\x5d\x00\x1f\x6c\x7a\xba\x2d\x9b\x1e\x80\x1b\x2d\x2e\x2a\x2d\x1a\xfe\x9b\xe2\x71\x62\xd1\x8b\x12\xb0\xe6\xc4\x97\x6c\x48\x22\x71\x13\xa2\x90\xd6\xa8\x72\x81\xe0\x41\x5f\x80\x7c\xaa\xce\x10\x83\xb4\x72\xc4\x2c\x0f\xfd\xd4\xf9\x72\xdc\x29\x24\xca\xd3\xe5\x83\xf1\xc9\xf8\xdd\xb8\x9e\x45\x6d\x92\xfe\xfa\x71\x97\x45\x3f\x74\x9c\x78\xc5\x29\xf8\x10\xa4\xf2\xc4\x8b\xfd\x6a\xd7\x2d\x69\x5b\x1a\xc7\x69\xa7\x2e\xc1\x13\x35\x31\x40\xda\xfc\xde\x46\x15\xa6\x32\x85\x55\xa0\xad\xc7\x1b\xde\xb8\x7e\xbc\xc1\xdf\xb3\x78\x73\x0f\xaf\x02\x69\x6e\x5e\x9b\x10\xa6\xdb\xf3\x7b\xe4\x1d\xcf\x75\xd2\x39\xaf\x73\x8f\x0e\x09\xa6\xd2\x62\x97\x52\xee\xee\xb7\x75\xd4\x7b\x11\x10\x2f\x95\xb6\xe9\x45\xb3\x27\x9d\x1e\xa0\x9f\xa2\x3f\x82\xd6\x60\xd8\x67\x1b\x23\xb7\x80\xce\x6c\x0e\x6c\x4f\x1e\x4a\xcf\x52\x67\x4c\xfe\xd8\x81\xfb\x30\xfc\x6a\xc2\x32\xed\xb0\x2e\x35\x98\xd4\xfd\x4d\xe0\x9f\xd9\x73\x92\xa6\xed\x21\x2c\xcf\x39\x2c\xc4\x7c\x61\x96\x9a\x6b\x50\xe9\xba\xda\x83\x6f\xa4\xb7\xac\xf2\x4e\x4e\x2c\x7a\x6c\x02\xfb\x8e\xf4\x78\x26\x11\xf8\x92\xb0\x14\x32\xe0\x90\xa7\x66\xcd\x05\x9d\xd6\xe9\xbf\x64\x14\xdf\x05\x3d\x23\xae\x64\x34\xf4\x83\xd9\x8c\x72\xc0\x67\xcf\x3a\x5e\xae\x8c\x2b\xf9\xdf\x25\x99\x88\xd1\x5d\x38\xf4\x89\x9b\x0a\x8a\x59\x61\x5e\x7e\x95\x79\x19\x82\x6f\x95\x8c\xef\xa1\xe2\x51\xe8\x2e\x5c\x6f\xa8\x9c\x72\xe5\xc7\xca\x78\xbc\xc6\x82\x04\xa5\x5f\x6e\x98\x42\xdc\x16\x88\xd0\xf0\x53\x46\xe7\xd5\x0e\x40\xd4\x07\xb4\xab\x8e\xe7\x3a\xd1\xcd\x55\x1b\xf6\x76\x6b\x7e\x05\xbb\x93\x9f\xb4\x4a\x6f\x4f\x4d\x1b\x00\x75\xb1\xd9\xe2\x51\x51\xbd\xbe\x21\xa3\x7c\x97\x11\x30\x95\xad\xed\x64\xa9\x82\x0f\x00\x4b\xed\x79\x40\x7c\xc9\x58\x4d\xbd\xb2\xd3\x54\x72\x03\x2e\xb8\x81\xaf\xb8\x81\x5d\xbe\xe8\xe3\x8b\xf8\x56\xd3\x13\x3c\xeb\x98\xd7\x0e\xc2\x2c\x2e\x49\x26\x17\x44\xef\xdc\xb6\x37\x4a\xa0\xaa\xcb\x43\x99\xf4\x49\x9e\xa7\xca\x07\x24\x4e\x82\x69\x10\xd1\x70\x5b\x1d\x81\xdf\xb4\x43\x45\xbb\xfc\xa9\x9b\x5d\xd9\x11\xd0\x3d\x41\x1a\xc6\xb6\x0f\xec\x48\xd2\x87\xdd\x36\x00\xd0\xaf\x3c\x14\xaf\x3c\x11\xaf\x5c\xc9\xd6\xe3\xf4\xc6\x22\x12\x89\x4f\xbd\xab\x36\x57\x93\xd4\xe7\x3c\xdc\xf0\x28\xd1\xce\x26\x5e\x90\x52\x16\xfe\xa9\xf2\x11\xfb\x5d\x24\xf7\x07\x8d\xec\x04\x54\xb5\x05\x38\xd4\x2b\x4b\x3d\x2f\xf1\xd3\xb4\xc3\x17\x67\x5f\x70\x37\x38\x4d\x1d\x99\x01\x77\xe9\xa3\x2f\x89\x1f\x90\x53\x97\x1c\x0a\xba\x50\xa4\xbf\xd5\x1e\x39\xe3\x54\x65\xcb\x95\xdd\x94\x59\x72\xaf\x5c\xb2\x9b\xa2\x28\x76\x91\xde\x98\x43\x88\xdb\x1c\x68\x66\x67\x40\x73\xdb\x07\xfa\xd6\xa6\xc0\x42\x3b\x01\xf6\x5c\x4e\xff\x3c\x2d\x9c\x83\x78\x20\xc6\xf9\x52\xfa\xce\x44\x93\x60\x6a\xc0\x3c\xd5\xae\x46\x7e\x92\x06\x71\x74\x1c\x4d\x62\xed\x2f\x34\x8d\x3f\xc8\x9b\x95\xaf\x66\x59\x10\x7a\x07\xe8\x47\x54\xbf\xf7\x3e\xf5\x93\xea\xbd\x84\x46\xee\xac\x96\x47\x38\x0f\x36\xfa\xca\x2b\xbd\x5f\xb9\xe4\x22\xd5\xee\x36\x6a\x8a\x61\x96\x62\xe6\xb1\xd3\x54\x3c\xbe\x94\x8f\xe1\xb8\x9b\xc5\xd5\xe5\x07\x2d\x06\xc9\xba\x8f\x98\xe6\xed\x3c\xad\x0b\x11\x89\x10\x22\xe4\xa9\xc3\x49\x07\xe9\xd3\x39\xbc\xbe\x6d\x42\x7e\x35\x55\xe4\x48\x05\x94\xa4\x50\x08\xf5\x27\x29\x8c\x69\x85\x60\xb0\x2b\xfb\x07\xbb\x46\x22\xa6\xe8\xb1\x09\xd7\xad\xec\x1c\xa5\xe9\x59\x5c\x53\x24\x65\x89\xd5\x88\x5b\x61\x2c\x3d\xdd\x9c\xa8\xac\xa7\x1a\x24\xc5\x6d\x2b\xf1\xc3\x98\x7a\xe4\xce\x8e\x20\x0c\xe6\x1a\xce\xba\x56\x2b\xb1\xd8\x6b\x99\x00\xe0\x55\x33\xce\xeb\x91\xa2\x61\x2b\xb2\x9c\xc0\x3e\x56\xd7\x3c\x91\x16\x50\x0c\xd1\xc1\xc0\xf1\x06\x7f\x3c\xb1\x33\x8b\x02\x7b\x6a\xbb\xe0\x5e\xdb\x29\x27\x58\xbc\x86\xd6\xcd\x1d\x2e\x04\xa2\xd7\x14\xdc\x54\x10\xb4\x03\xd5\xab\x20\x3d\xc8\xec\x04\xef\x6d\xb2\x3c\xdd\xa9\x27\x3a\x05\xf7\xc0\x2e\x64\xf7\x4b\x0a\x85\xf4\xb6\xb3\x19\x9e\xe6\x5e\xdb\x0b\x5e\xd7\x4f\xc6\x94\x28\x7e\xe6\xaf\xab\x81\x41\x52\x3d\x11\x53\x61\xce\x25\xb9\x4a\x41\x89\x6f\x93\xb5\x98\xe6\x58\x4c\x0f\x15\xae\x67\xb4\x9a\x53\xa2\x1c\xa7\xcf\xc9\xc4\x04\x77\x6c\xa7\x7a\x66\xbb\x95\x99\x3d\x2d\xa3\xe2\x9a\xaf\xe6\x9c\x84\x85\x16\x85\xb0\xb3\xc2\xa4\x23\xdf\xa4\x56\x3a\x0e\x48\x58\x51\x0e\xd1\xe0\xd0\xde\x51\xc8\x49\xde\x54\xc7\xa6\x13\xa1\xa7\xb5\xc5\x4e\xe9\xf7\x9e\x67\x35\x66\x79\xbf\x3d\x4a\x2a\x2a\xc5\xe4\x9d\x07\xd5\x26\xd7\x29\xa9\x3e\x7b\xd4\xfe\x3a\xaf\x04\x16\x16\x6d\x1f\xab\x50\x34\xb1\xee\x7d\x07\x3d\x34\x3c\xa1\x7a\x6a\x07\xa8\xcd\x70\x34\xf6\xd4\x7e\x2b\x96\xe6\x29\x26\x7d\xea\xaf\xeb\x02\xdc\xc3\xea\xc8\x4d\xbd\xec\x92\x7c\x53\x0a\x16\xf8\x35\x51\x71\x21\xe1\x5c\x4a\x5d\xec\x04\x70\x00\xcc\xe9\x42\x5b\xa2\xb7\xd8\x89\xbd\x40\x8e\x4f\x6b\x36\xe1\x99\x04\x6b\xd9\x89\x7b\x20\x3b\x11\x60\xfd\x8c\x3a\xb3\x26\xc4\x1c\xd8\xb1\x33\x2b\xa5\xb8\x1a\x18\xab\xa0\x2f\x04\x43\xd5\xdf\x58\x76\xd4\x8c\xfa\x12\x10\x57\x8d\xfa\xaa\x42\xdd\xfd\x22\xd8\x8b\x16\x1d\xed\xeb\x39\x35\xe3\xbd\xdc\x7d\x15\xef\x55\xa0\xec\x6f\x9b\xe2\xe4\xdb\x4d\x21\x6c\x67\x33\x02\xcc\x65\x8d\x26\x4f\x37\x7b\xf9\xb6\x4d\x31\x96\x4d\x1e\xd4\xe5\xd6\xbd\xd4\x79\x03\xef\xda\xa8\x25\x99\x93\xbd\x14\xa9\x3e\x66\x16\x7b\xe3\xc3\x0e\x44\xa6\x1d\x99\x77\x8d\x7b\x74\x19\xdc\xcb\xef\x1b\x6b\x78\xdb\x4a\xdb\x69\x62\xdf\xd9\x11\x7a\x76\x04\xf4\x1b\x3a\x22\xf5\xed\xfe\x7a\x0d\x07\xdd\xa2\x41\x3d\x1a\xd2\x8f\x95\xf6\xce\x1e\x08\x91\xe1\xd8\x7e\x8b\x5a\x0d\x3d\xb7\x85\x2c\x09\x6a\x00\x19\xc3\xcd\x9e\xd8\x7d\xa0\x27\x6a\x44\x1f\xdc\x05\x76\x35\x14\x77\x77\xd0\x4f\x73\x2e\x45\x3d\x9c\x0f\x9b\xe2\x71\x98\x0e\x00\x77\xe7\x82\xcf\x8b\xb6\x6c\x26\xfe\x91\x11\xcb\x45\xb4\xb7\x78\x0d\x43\x09\x75\x36\x94\xb5\x09\x47\xa9\x23\xd8\x8d\x1f\xaf\xe1\x7b\xa7\x76\x99\x58\xfd\x51\x84\x87\x0b\x26\xbc\xee\x54\xcc\xb5\x4b\xb4\x33\xa3\x24\x91\xc9\x6a\xbf\xa7\xf2\x94\x7c\xa6\x8a\x8e\x19\xcb\x24\xf6\x32\x7c\xd5\x80\x97\x13\x0c\x79\x85\x89\x13\x8f\x12\x8b\x4e\x6c\xb1\x3b\xac\xed\xad\xe9\x46\x8e\x4a\xfd\x66\xda\x12\x38\x1c\x54\xd4\x8b\x3a\x5e\x07\x8d\x14\xd1\x3d\xca\xd6\x6b\x62\x42\x28\x07\xc5\x2c\xc6\xc5\xa0\xde\xc6\x49\x9a\x90\xbb\xd0\xf3\xd1\x79\x97\x12\x3d\x63\x95\xd4\x4e\xb0\xd5\x70\x16\xa7\xdc\x7e\x3a\x7c\xfa\xe0\x9e\x51\x91\x1e\xce\x52\xb8\xc2\xf5\x20\xd4\xf9\x21\xf7\xde\x75\x38\xee\x9f\x5b\xea\xa8\x02\x38\xf6\xec\x9d\x35\x64\x4e\xcd\x90\x88\x3b\x8a\xd2\x3d\xea\x10\xf1\x1a\x7c\x67\xd3\xd2\x38\x65\xaa\x99\xb4\x00\x09\xc2\x33\x27\x07\x29\x70\x60\x26\xb0\x57\x76\x0e\xec\xb5\xd8\xbc\x09\xb0\xb7\xa8\xc5\x7c\xb3\x43\x01\x8a\x4c\xf0\xe0\x14\x5c\x8c\xd3\xc5\x1e\xdc\xd0\x9e\x08\xf6\x19\x80\xbb\x2f\x60\xef\xc0\xa6\x82\x55\x65\x42\x50\x3f\x4a\xd7\x28\xff\x7c\x48\x0b\xaf\x3c\x81\x06\xf0\x22\x75\x58\x42\x0c\x2f\xc8\x0d\x13\x5e\xc9\x8b\x74\x49\x23\xc3\x84\xe7\xa9\x33\x49\xe0\xbd\x10\xee\x5f\xa4\x80\x27\x7a\x73\xf2\x4a\xfd\x7a\x9e\x12\xe3\x24\xa6\x5e\x10\x4d\x2d\xcb\x32\xcc\xaf\xd2\x55\xff\x73\xab\xa8\xf3\x8e\x44\x16\x8f\xdf\x2f\x97\x7e\xb2\x4f\x53\x1f\xbd\x27\xdf\xa4\x2d\xa7\xb3\x14\x8b\x7d\x34\x9d\x58\xa2\x5a\x9d\x3d\x5e\xcd\xf6\x94\xfb\xf0\x39\x45\x97\x2d\x4c\x6f\xff\xb1\x13\x0b\xe6\x64\x99\x40\x04\x73\x1d\x71\xf6\x29\x75\x3e\xa6\xc4\x70\x43\x9a\xa6\xa7\x42\x3a\x37\xe1\x4b\x87\xa0\xf6\x22\x15\x9f\xfc\x29\x25\x32\xc1\x5a\x0f\xff\x1d\xac\x68\x12\x09\xcd\xc5\xfc\x6a\xaa\x15\x79\x83\xe6\x19\x0c\xa2\x7c\xf9\x2b\xf6\x29\x69\x9c\xd2\x6c\xa1\xae\x5c\xbf\x4f\x37\xa1\xfe\x4b\x5a\x58\xa4\xa2\x10\x37\x8c\x65\x9c\xc7\x62\xcb\x12\x79\x1d\x06\x86\x09\x3c\x74\x66\x09\xf8\xa1\xb3\x48\x20\x0b\xbb\x57\xc5\x0f\x65\x05\x39\xac\x53\x8e\xac\x96\x86\xed\xcb\x90\x85\x42\x5a\x0f\xdc\xb9\x21\x04\x75\x34\x44\xb9\xe1\x76\xdf\x9f\x24\xd4\x2b\x17\xd1\x7c\x10\x70\x7f\xa1\x97\x4b\x65\xcb\x41\x88\xaa\x34\x09\x83\x68\xde\x53\xf1\x07\xa2\xa5\x6f\xda\x73\x12\x85\x12\xf8\x78\x08\x06\xa3\xee\x5c\x10\x94\xc8\x33\xc0\xe0\x09\x8d\xd2\x25\x4d\xfc\x88\x1b\x82\x33\x8a\x06\x93\x38\xe2\x06\xd6\x03\xf4\x93\xa0\xbc\xed\x66\x49\x2a\xe8\x80\xb1\x8c\x83\x08\xf3\x72\xab\x07\x71\x26\x14\x50\xdf\x00\x23\x8a\x23\x01\x05\xd5\xa9\x18\x62\x35\x64\x8c\x10\x4e\x46\xba\x49\x04\x6d\x0b\xa4\x6b\xbd\xa3\x07\x7c\x47\x83\xdf\x74\xa6\xdf\x8e\xe7\x8f\x75\xa6\xdf\xae\xfd\xda\x0c\xc4\x4b\x5b\xb7\xea\x65\x40\x82\x98\xcc\x09\x0b\xb1\x2c\xb5\x8c\x23\x80\x4f\x45\xfc\xc0\x1a\x3d\xf2\x42\x09\x2c\xd4\x30\x21\x97\x3f\x05\xd8\x78\x21\xa2\x05\x0f\x78\x28\x16\xa3\x1f\xb6\x3b\x51\x40\x2d\xcc\xb6\x8a\x22\x8c\x47\x03\xa4\xf8\xbd\x45\x32\xb8\xdf\x5b\xb0\xc1\x7d\xbd\xe7\xd5\xcd\x66\x3c\xea\x89\xa6\xe9\xa2\xc7\xe2\xc4\xf3\x93\x41\x12\x4c\x67\x7c\x30\xec\x71\xff\x92\x0f\x16\x19\xf7\xbd\x62\x8f\xb2\xd4\x4f\x06\xa9\x1f\xfa\xae\xdc\xda\x80\x07\x34\x2c\x9e\x0e\x16\xf1\xf5\xe0\x86\x26\x2b\x9f\xcd\x03\x7e\x43\x2b\x35\x11\x37\x0e\x11\x52\xfe\xe6\xba\x6e\x05\xbb\x93\xbb\xff\x70\x8c\x7f\xdc\xe5\x98\x03\x5f\xc6\x25\x45\x61\xdb\xe7\x4c\x07\x13\xea\xf9\x1e\x5e\x2b\xe8\x1a\xa4\xbe\x1b\x47\x1e\x4d\xae\x24\x44\xa5\x21\x91\x99\xfd\x4c\xb1\xe2\xc4\x38\xc4\x44\xa4\x3d\x76\xd5\xe3\xb3\x20\xed\x61\xb5\x9b\xca\xd0\xc6\x5d\x4d\x61\xd7\xb0\x68\xdb\xf2\xaa\xbd\x28\xf2\x57\x23\x99\xd8\xd4\x31\xee\xbe\x0e\x48\x1e\x4b\x5c\x9d\x75\xa0\xf5\xc7\x14\x8c\x59\xe2\x4f\x0c\xb8\xf7\x5f\x17\x34\xa7\xa9\x9b\x04\x4b\x6e\xdf\x0b\x64\x69\x48\x92\x38\x91\x69\x25\xfe\x32\xa4\xae\x4f\xee\xfd\x33\xbd\x37\x05\xc3\x30\xcd\x91\x61\xd8\x89\xa9\xab\x37\x2e\xdb\xe0\xe4\x9c\x93\x08\xed\xda\xd9\x66\xf1\xd4\x39\x09\x1b\x4b\xa7\x97\x2a\x88\x26\xb1\x86\x89\xa1\x61\xc2\x2c\x24\x04\x3d\x76\xbe\xc0\x22\x6c\x7a\x56\x15\x62\xbf\xeb\xa3\xf4\x3b\xd4\xa9\xd3\x39\xc1\x2c\xf9\x05\xec\xe5\xc5\x88\x13\xda\x9b\xd0\x01\xf3\xc3\x70\x90\x86\x34\x9d\x0d\x62\x84\x55\x5c\xf0\xbe\x60\x7c\xc4\x50\x67\x4f\xb8\xec\x45\xf6\xb9\xa4\xea\xbe\xd5\xfd\x01\x1e\x8d\xa6\x62\x33\x6b\x9f\x50\xb7\xe8\xf9\xb7\x98\x55\xd7\x9c\x3c\x43\x02\xc2\x34\x94\x3e\x5a\x9d\x94\x7d\x15\xeb\xd0\xc4\xce\x26\xd7\xba\x09\x19\x93\x3f\xca\x1c\xbf\x65\x26\x5f\x2c\xf3\xb5\x6a\x92\xa3\x5a\x0a\xcd\x3b\x51\x25\xa8\xff\xd9\x46\xdc\x8a\xd8\xf9\x69\x28\xf6\xa2\xc8\xb2\x59\x30\x78\x2a\x78\xa1\xb4\x41\x24\x78\xda\x29\xa3\x5b\x64\x39\x75\xcc\x36\x74\x9c\x11\x74\x81\x9b\x73\x38\xcf\x48\x86\x91\x2d\x52\xf5\x29\xf3\x70\xde\xf2\x65\x7c\x35\xa9\xbf\xda\x68\x9c\xc8\x9c\x77\xbd\xf6\xa9\x36\x46\x38\xcf\x08\x51\xc3\xcb\x92\x28\x5c\xea\x55\xb7\x98\x9c\x9c\xd1\xdd\xca\x98\xf5\x87\xf2\xc1\xda\x84\xab\x56\xbc\x1d\x13\x1d\x61\x64\xa5\xcb\x30\xe0\x02\x33\xef\xde\x9b\x62\x60\x8a\x22\xe1\x34\x99\xfa\x82\x01\x5e\x76\x20\xfe\x06\x22\xd5\x5d\x96\x9e\x4b\x75\xbf\x2d\xe7\xad\x84\xfc\x59\x28\xc4\xe2\x79\x48\x8c\x6f\x2c\xa4\x82\x55\x96\x94\x52\x02\x28\x26\x84\x5a\x85\x70\x15\x62\x35\x0f\x64\x3a\xbb\x92\xd3\x70\x41\xdb\xc7\xea\xf7\xcc\x30\x61\x5f\xfd\x16\x7c\xf9\xf0\x96\x3c\x67\x3f\xd4\x52\xe9\xb8\x40\x22\x64\x1e\x51\xbc\x4a\xe8\xb2\x46\xba\x0d\xdb\x50\x34\x7b\xb7\x68\xbb\x1a\xec\x0c\x87\xd8\xea\x12\xe1\x13\x27\x7d\xda\x29\x2a\x09\x89\xe5\x94\x0b\xd9\xeb\x85\x29\x04\x17\x49\xfc\x69\x88\x65\xdb\x6e\x24\x64\x55\xa1\xa6\x15\xf1\x17\x41\x94\xa5\x0d\x9c\x47\x43\xad\x98\x99\xdd\xc6\x6d\xba\x48\x26\x0d\x49\x31\xd3\xae\xf1\x96\xe1\xb6\xe1\xd6\x26\x5c\x74\x80\xcd\x2f\x51\xee\xa8\x73\x7c\x7c\xc3\x9d\xd1\x84\x37\x09\x5d\x9c\x25\x8a\xf6\xae\xe1\xbc\x75\x1a\xd1\xef\x3b\xc3\x91\x31\x54\x25\x5a\x6d\xfc\x77\x0d\xc7\xad\x6d\xcf\x05\xd7\x90\x21\xe9\x82\x97\xc9\xe8\x73\xbc\x29\x03\xd2\x93\xea\xad\xeb\xf2\x16\xc8\x0a\xb0\x9b\x11\xff\xe7\x21\xf9\xff\x2b\xda\x1f\xd7\xa5\x12\xe9\xdf\x23\xef\xdf\xed\x9b\x86\x66\xfd\x27\x1d\x70\xf2\xaa\xa2\x35\x05\xd3\x48\x88\x5d\x93\x81\xeb\x0b\xe1\xbb\xdc\x71\x89\x9f\xc7\xa1\x10\x14\x56\x0a\x05\xbf\x35\x51\xb0\xc2\x6c\x06\xf7\xbb\x74\x43\xef\x59\xe4\xcc\xc9\xb7\x50\x06\x51\x58\xbe\xa9\xd3\xae\x5f\x77\xcc\xf0\x5b\x28\xa4\x05\x73\x0d\x67\xb5\x11\x33\x28\xa8\xce\x2d\x93\xea\x66\x24\x32\x47\x67\x44\xd5\x68\xc2\x9a\xec\xf6\x19\xe1\xa0\x6e\xf8\xd5\xc4\xdb\x18\x3e\x93\xc0\x19\xe9\x0b\x70\x97\x79\xdd\x43\x27\x4c\xe0\x9d\x22\x81\x94\xa1\xe4\xfd\x36\xdc\x66\xa9\x71\x8e\x08\xf1\x9d\x39\x39\x0b\xa5\x2d\x79\x8f\x42\xe4\x93\x4a\x02\x70\xb3\x9a\x62\xb2\x93\xff\x9f\x15\xfc\x3f\x32\x31\xcf\xa4\x90\x9a\x2c\xfa\x45\xc8\x4d\xe2\x23\x2d\x56\xb1\x85\x24\x15\x35\x6c\x19\xa7\x81\xb4\x03\xe1\x09\x4c\xe0\x2a\xc5\x49\x6e\xb5\x50\xf4\xd2\x01\x46\x60\xf7\xc2\x20\xe5\x52\x21\xc0\xdb\x25\x41\x5c\x0e\x86\x42\x3b\x78\x58\x92\xc4\x52\x89\x40\xd2\x8c\xba\x43\xcf\x1b\x4c\x42\xff\xb2\xd7\xe8\x58\xbf\x76\x22\x68\x37\x0c\x7f\xbf\x0e\xc5\xcc\xbf\x0b\xca\xbc\x17\xb6\x49\x88\x2f\x03\x52\x16\x4a\x5f\xc3\x9c\x9c\x86\xb8\xa8\xa6\x2d\x68\x8e\x61\x02\xc1\xdc\x87\xaf\x21\xb3\xfa\x23\x79\xcb\xbe\x08\x31\x8a\xcb\x84\x25\x8e\xd2\x2d\xe2\xd2\x8f\x9b\x22\xae\xec\xe1\x36\xf2\x62\x9d\x4f\x20\x07\x0b\x14\x1d\x6e\x27\x9d\xfe\x95\xdf\x21\x22\x1e\x17\x65\x80\x10\x95\x08\x47\xa6\x77\x48\x12\xc1\xb9\xb8\xe6\x5c\xef\x4a\x76\x29\x80\xad\x57\xac\xf6\x0e\xf6\x85\x92\xc1\x61\xa8\x60\xe1\xbb\x59\xae\x90\xb2\x04\x61\x83\x7e\x28\xe4\x30\xc9\x2a\x0e\x9a\x18\xab\xa4\xc0\x91\xa1\x59\x1b\xd6\x62\x43\xae\x63\x94\x8b\x52\xf0\xd0\xe4\x36\x2c\x74\x91\x0c\x76\xd4\x34\x95\xc6\xb6\xa0\xc9\x34\x88\x06\xa1\x3f\x11\xfa\xdc\xe0\x41\x52\x1a\x18\x36\x96\x4d\x48\x5a\xb8\x4e\x72\xc6\x47\x12\xd9\x32\xa1\xfc\x7d\x0f\x6f\x88\x44\xe2\x16\x1b\x75\x47\x74\xdc\x52\x15\xde\x29\x17\xb8\x45\x15\xfe\xcf\x51\x7a\x1f\x31\x77\xe8\xf9\xbf\xaa\xf7\x56\x37\xec\x4f\xab\xb8\xdc\xb4\xbb\xac\x05\x5a\x8d\x6e\xae\xa8\xe8\xe3\x34\xe6\x3d\x5c\x70\x85\x00\x5f\x4d\x08\x1c\xfa\xf3\x27\x66\xa0\xcb\x40\x99\xb5\xb7\x91\x87\xa7\x25\x79\x38\x08\x21\x80\x0c\x2d\xdc\x5f\x28\xf1\x4d\x60\x0e\x46\x6d\x8d\x32\x97\x4c\x04\x1b\x44\x62\x6b\xd8\xb5\xcb\xd4\x00\xf4\xad\xaa\x4e\x7e\x11\xca\xa9\x0e\x8b\x35\x5f\xcd\x02\xee\x0f\xd2\x25\x75\xa5\xdd\x69\x43\x5c\x65\x72\xee\x35\x90\xea\x6f\x92\xc8\x05\x1b\x3c\x50\xe8\x3a\xe7\x10\xc3\x11\x71\x01\xfd\x13\x82\xd1\x9c\x1c\x15\x1b\x54\x92\x5f\x35\x05\x8d\xe0\x73\xf2\x36\x04\x0e\x91\x60\x56\x1a\xc1\x25\x6e\xbc\xee\x14\x81\x57\x24\xa1\x80\x01\x94\xe0\x66\xe0\x66\x68\x51\xae\x99\x00\x25\xe6\x68\x6d\x82\xe9\xbf\xa5\x7e\x58\xfd\x84\x65\x38\x78\xa4\x26\xd4\x1d\x99\x12\x92\xef\x21\x22\xe4\x18\x25\xda\x2f\x26\x60\x62\xd3\x08\x70\xf4\xc8\xac\xa8\x28\xe2\x3e\x75\xc6\x98\xd9\x51\xb4\x7c\x56\xef\x62\x4e\x5e\x87\x58\x9d\x1a\x28\x24\x30\x14\x1d\x94\x26\x55\xe3\x34\x96\x3b\x28\x01\x28\xed\x4d\xd0\xc6\x88\x01\x8e\xca\x3a\x16\x2d\x33\xa1\x4e\xbd\x52\x46\x56\x09\xc0\xf0\x7c\x8b\x6d\x15\x2d\xce\x2c\x56\x16\xe7\xf7\xa1\xf3\x3c\x24\x86\x3b\xf3\xdd\x39\xe2\xf9\x67\xa5\xa8\x5d\x2d\x05\xc3\x7f\x13\x96\xce\x9d\x4a\x77\x83\xa2\xf1\x57\x13\x8f\x4d\x3e\x6e\x33\xcd\xce\x68\x34\xc5\xc4\x2f\x49\x00\x11\xbc\x09\x05\x2a\x7d\x6a\x93\x22\x6e\x61\x9e\x9d\x93\x57\xc5\xb3\x05\x17\xf0\x2b\x80\x58\x56\x7c\x1b\x08\xf5\x36\x89\xc3\xe2\x52\xcc\x91\xc5\x97\x15\x46\x8e\xef\x7e\xd6\x1f\x8b\xcf\x90\xbe\xd7\x3b\x18\xe8\x25\x7d\x1f\x16\xf5\xea\x12\x53\x7c\xa5\x2c\x9f\xc9\xe1\x65\x60\x2a\xee\x56\x45\xa8\x46\x2f\x5e\xe0\xe2\x29\xcf\xcd\x6d\x3d\x5f\x9a\xb7\x84\xe8\x52\x22\x5c\xa4\x48\x8f\x84\xff\x2f\xad\xd6\x59\xfa\xd9\xbe\x8f\x7e\x65\x9f\xd0\x6d\x08\x9d\x76\x8b\x6c\x2c\x2f\x43\xa7\x51\xe2\xfd\x30\xab\xc6\xee\x2d\xb2\x32\xba\x2e\xca\x8b\xe8\xba\x97\xa1\x2c\x58\x9c\x88\x5b\xb9\x0b\xc6\xdc\xbf\xda\x8f\x3d\xdf\x00\xcc\x86\x62\x02\xcf\xbb\x77\x7c\xee\x5f\x79\xf1\x2a\x2a\xb6\x3c\xc9\xb1\xca\xef\xf6\x37\xb2\xe5\x46\xfb\x4c\x0c\xfd\x9a\x17\xb5\x2b\x0f\x7d\x13\x84\x4a\x4b\xf3\x5b\xe6\x9f\x72\xdb\x06\xac\xf8\xbd\x06\x1d\xcf\x8b\x7c\x31\xb9\xf3\x0f\x3f\xca\x9d\xea\xf1\xe2\x3f\x60\x92\x3b\x4f\x80\xe5\xce\xce\x03\x48\x3b\xbe\xa8\xa4\x24\xae\x80\xc6\x38\x1c\xd0\x8c\xc7\x6d\xf2\xe4\x56\xa3\xf4\x6d\xb8\xd9\x9c\xd0\x1c\xee\x08\x6d\xa1\x84\x9a\xe7\x81\x3a\xee\xd9\xca\x11\xa5\x35\xb0\xda\xcb\x4e\xad\x17\xe3\xff\xfc\x6f\xa3\x02\x7e\x10\xb6\x7e\xec\x2d\x2c\x9f\x0f\xa1\x48\x13\x24\x63\x6f\x64\xc6\xd0\x3c\x97\x87\x7a\x0b\x1a\x0a\x72\xe5\xe5\x48\x84\x0a\xdf\x3a\x13\xfa\x39\x52\xa1\x40\xfc\x5e\xc8\xdf\x32\x21\x95\x09\xb3\xd6\xb9\x9c\x91\x08\xee\x0c\xcd\x35\x2c\xbb\x20\xa4\x72\xac\xb4\x53\x1c\x2b\x4d\xf3\x16\xfa\x26\x47\x52\x4e\xec\xab\x8e\x7d\x5e\xe6\xa0\xa8\xaf\x84\xdc\x59\xae\x21\x78\x9a\xa3\x55\xe9\x2a\x6f\xb7\x18\xf5\x65\xa8\xe7\x37\x99\x25\x21\x81\xcc\x89\x72\x74\x86\x76\xa8\xa2\x38\xfd\x58\x66\x1c\x63\x21\xe6\x3c\xc2\xd2\x47\xae\x93\xe5\x42\x20\x0d\x9c\x43\x92\x21\x2a\xc4\xaa\xe0\x48\x28\x44\x88\x89\xf4\x60\xe1\x23\xc3\xb0\x85\xaa\x60\xcc\x68\xaa\x77\xd9\xc6\x8b\x34\x73\x5d\x3f\xad\xca\xb9\x25\x24\x26\xf1\xaa\x17\xc5\x83\x69\xc6\xb9\x9f\xa4\x1d\x6a\xcd\x91\xdc\xec\x34\x17\xe3\x6d\x80\xb2\x00\x75\xe3\xee\xa4\x90\x80\x83\x68\xb0\x0a\x3c\x3e\x33\xc0\xb8\x3f\x1c\x2e\x2f\xdb\xc0\x1f\x17\x4f\x22\xc0\x26\x91\xee\xe7\xed\x65\xd0\x90\x5c\x4f\xe2\xa4\x20\x9d\x08\x1d\x62\xf1\x78\x4e\x36\xcc\x86\x87\x24\x02\x96\x57\xc2\xeb\x5b\x17\x56\x17\xe0\x98\xe4\x66\x59\xa7\x83\xeb\xdd\x3a\x23\x3e\xb8\x95\xa0\x48\xfa\xf3\x67\x62\x31\xab\x3f\xea\xc7\xb6\x46\x3e\x71\x83\x16\x4c\xdb\xcd\x45\xcf\x45\x11\x9e\x78\x6d\x82\x9f\xb7\xc5\x3e\xab\x41\x47\xe2\x85\x1d\xd3\xc6\x96\xab\x9c\x04\x79\x0b\xbb\xa8\xac\xd4\x80\xf1\x68\x1b\x91\x58\x26\xc1\x42\x1e\xe8\x78\x39\x09\x4c\xa0\x2d\xb2\x2c\xfc\xa2\xb9\x2c\xcc\x49\xfc\x17\x9c\x58\xc8\x91\xf3\xbc\x78\x5d\xec\xa3\x50\x31\x6a\x7a\x46\x39\xdf\x7d\x64\x92\x3d\xb5\xf9\xd0\xf3\xad\xa9\x65\xb4\x93\x35\x3c\xa0\x55\x27\x5d\x12\x78\x19\x4d\x7d\x3c\x41\x45\x12\x17\xe4\x24\xce\x2b\xe4\x2d\xce\x4b\xe2\x86\xc9\x95\x61\x9e\x6f\x13\x49\x4a\xb1\x63\xf2\xb8\xe7\x05\xac\xb7\x60\xf7\x7b\x8b\xa4\xd5\x0e\x20\x8d\x49\x37\x88\x1d\xef\x51\xb9\xfc\x18\x12\xde\xb2\xdd\xcb\xb0\x66\x87\x32\xd0\x77\xb8\x10\x04\x2e\x3b\x18\x97\x3e\xc6\xdd\xed\x78\xae\x93\x44\x8f\xb7\x70\xd0\xda\x31\xee\x7e\xb3\xa1\xd4\x9f\xb5\xcd\xd9\x34\x47\x45\x56\x3e\xa3\xa1\x3f\x8b\x2f\xf1\x92\x78\x29\x84\x01\x69\x64\x91\x07\x11\x82\xc6\x8d\x25\xe6\x98\x9b\xd6\x79\x13\x0e\xb7\xc8\x09\x8b\x38\x4b\x7d\xb9\xba\xc5\x59\xff\xe9\x4d\xed\x43\x9f\xe6\x7e\xd9\xfe\xa2\x63\x75\xf4\x21\xf7\xb9\x60\xf0\xc7\xb9\xf3\x70\x08\x27\xc8\xe6\xbf\xe5\xce\x83\x27\x70\xdd\x5c\x8b\xf6\xba\x8b\x65\x51\xcc\x44\x17\x33\xc2\xd2\x52\x05\x1d\x3a\xe7\x84\x9b\xb5\xf2\x8b\xb7\x95\x68\xf6\x3a\xa6\xae\x23\x7d\xde\xdd\x20\xd1\xbc\xbd\x41\x22\x3a\xd8\xb2\x94\x2c\xcc\x2a\x8b\x7e\x94\x37\xca\x22\xcb\x3a\x25\xc8\xd1\x8e\x64\xf2\x82\x21\x26\x2f\xa0\x3b\xe8\x65\xcb\x9e\x60\x91\x69\x9a\x20\xd7\x3a\xe3\x90\xe5\xb2\x28\xd5\xbb\x2d\x76\xc0\xeb\x5c\xdb\x01\x3f\x70\xac\xcf\x41\x51\xef\xe5\xa3\x03\x41\x7d\x25\x0c\xa1\x06\x8c\x3d\x9e\xf3\x5f\xe9\x31\x93\x07\x76\x2d\xbc\xf0\x06\xb6\xb4\x59\xbf\xa8\x83\x25\xf9\x5d\x2c\xe9\xb8\x64\x49\x6f\x73\xc2\x0a\x06\xf4\xad\x76\x3f\x2e\xee\x9f\x94\xf7\xf9\x08\x3f\xf4\x40\x31\xb1\x31\xb2\x1a\xf1\x19\x95\xd5\xd0\xaf\x9d\x57\xf9\x99\x5f\xf2\xb3\x2c\x27\xae\x09\x41\x95\xa7\x59\x7d\xe4\x6a\x72\x55\xcf\x14\x4f\xa3\x15\x9e\xf6\xae\xc6\xd3\x0e\xb6\xf3\xb4\xf3\xdc\x1c\xbd\x93\x3c\xed\x40\xf1\xb4\x8b\xdc\x04\x92\x38\x7b\x72\xbe\x12\xa0\x64\xad\x55\x01\x51\x58\x17\xed\x20\x27\x7b\xf8\xd2\x5f\xc8\xfd\x24\xb1\x99\xb4\x59\x73\x24\xad\xf9\xfe\x9f\x20\xc1\x9f\x35\x24\xf8\xe8\x17\xa5\xf7\xb3\x1b\xa5\xf7\xd7\x1d\x94\xbc\x4c\x39\x2b\xf1\x36\x96\x98\x3a\x71\xee\xa0\x6d\x2a\x80\xc8\x72\x17\x58\xeb\xf9\x2c\x86\x00\x62\x81\x6b\x47\x3e\x09\xd0\xcd\x62\xb2\x45\xc6\x04\xe5\x9f\xb7\x69\x15\xc2\xb0\xb5\x79\x0e\xc6\x38\x42\x1b\xaf\xd4\x83\xa5\x71\x03\xab\xb5\x27\x70\x99\x57\xc3\x2d\x93\x51\x69\x67\x4a\xe1\x5f\x15\x59\xbf\xe7\x62\xee\xad\x22\x2b\xbb\x85\xc8\x7a\x94\xc3\x04\x22\x13\x88\xeb\x08\xd4\x3b\x8b\xa1\x72\xa4\x01\xae\x39\xfa\x15\xa9\xe6\x84\x32\x3f\xec\xcd\xfd\xab\xde\x24\x4e\x8a\x2f\xd7\x76\x3a\x75\xa8\xfa\x17\x75\xf7\xa7\x64\xa6\x8b\xbc\x7e\x72\x53\x8e\x59\xb9\xab\xe4\x27\x99\xd6\x1a\x4b\x26\xec\x60\xcd\x04\xa4\xfe\x77\xb8\x45\x4f\xfe\xfe\xf7\x3b\xdc\x62\xf3\x9f\x3f\x8f\x62\x92\x21\xe0\x18\xe9\x2c\x5e\x19\xb5\xcd\x14\xf8\xe5\xc6\x8b\x65\xe8\x73\x7f\xb0\xf0\xa3\xac\x67\xdc\xa5\x42\x18\x20\xbb\x48\x34\x4c\x38\x95\x3f\x77\xcc\x16\x2c\x2c\xa4\x0c\xf1\x66\x69\x4b\xdc\x47\x2a\x9c\xc9\x19\x7e\x2d\xfe\x60\x94\xc4\x87\xdc\x11\x4c\x7f\x0d\x2f\x6e\x60\x9a\xaf\x6e\x90\xa6\x9e\xdf\xc0\x94\xdf\x77\x3c\xd7\x51\x8d\x9f\x6f\x21\x64\xb5\x0a\x53\xe5\xc9\xbd\xdd\xf6\x7c\x9b\x8b\x21\x0d\xc9\x8b\x9c\x24\x96\xbb\x6a\x18\x74\xb9\x16\xc7\x2c\xfa\x50\x51\xc9\x37\xb9\xca\x81\xfb\xb1\x93\x8a\x48\x06\x1c\x09\x16\x5c\x96\x9d\x6c\x3b\x1f\xc7\x62\x5b\xa7\xfc\x86\x42\x73\x91\xe5\xae\xd6\x85\xe5\x27\xf2\x55\x32\x74\xd3\x34\x1b\xe7\x7e\x55\x2b\x61\x6f\xa1\x09\xb5\x00\xc7\x1d\x98\x93\x69\x02\x06\xa7\xec\x38\xf2\xfc\x4b\x4c\xa5\xcf\x65\x45\xc2\x8d\xb3\xc2\xc4\x0f\xa9\x5c\xcc\x0e\xef\xcb\x3a\xc8\xd1\x90\xbc\xc9\x25\xdf\x97\x46\xc8\x64\xf0\x70\xcb\x72\x97\x78\xf3\x56\x55\x41\xb3\x7b\xc6\x5d\x99\x03\x01\x3d\xcf\xfd\x0a\x4b\xfa\xd4\x69\xbc\x48\x2c\x96\x20\x9f\x9e\x8f\x48\xe6\x10\x8e\x49\xd0\x8f\x80\x3a\xdc\x62\x4b\x70\x0b\xa9\x0a\x91\x70\xf8\x4b\xa2\x95\xaf\x44\xab\xa0\x10\xa4\xfc\xdb\xbf\xef\xcb\x77\xb7\x6d\x08\xae\x50\xaf\x89\xe3\x48\x07\x10\xcb\x5f\x95\x58\xfe\x4a\x62\xf9\x9f\xd9\xa5\x42\x56\xdb\x2c\x3b\x27\x04\xb3\x0c\x85\x8d\x0f\x39\x4a\x26\xef\xf3\x86\x98\x56\x11\x65\x8e\x73\x73\xf4\x5c\x68\xd1\xb6\x12\xd0\xc4\x95\x2b\xaf\x4e\x72\x73\xf4\x22\x97\xe6\x9a\x0c\xba\x32\xfe\x4a\x48\xc6\x50\x3c\x36\x59\x2b\x98\xa9\x82\x8b\x4a\x33\x61\x08\x09\x3b\x76\xe7\xe5\x59\x8c\xe2\x44\x3b\xc3\xe1\xff\x28\x0d\xc8\x1d\x24\xaf\x57\xbb\x92\x2e\xab\x25\x19\xfc\x9c\x13\x74\x43\x47\xfa\x67\xcf\xc9\xc7\x1c\x22\x48\x2c\x36\x2b\x5c\x08\xb5\x10\xb0\x36\xe1\xcb\x16\x49\x41\xc8\x08\xb1\x14\xea\xcf\x65\xe8\xdc\x31\x0a\x0e\x6c\x2a\x05\x87\x3d\xc0\x20\xb6\x10\x98\xf8\x33\xc7\xec\x36\xec\xc1\xf6\xf3\x22\x97\x26\x5e\xaf\x2a\x1e\x6c\x3e\x1c\xcc\x7c\xea\x55\xd5\xe9\xa3\x2a\x98\xf5\x04\xa8\x71\xca\xd2\x5e\xa5\x2d\xde\xd0\x2f\xec\x12\x37\x84\x21\xa8\xe0\xb6\x20\xc4\x1a\x52\x0a\x1f\xe5\xe1\x9f\x74\xc1\xc2\x76\x3b\xcd\x76\x04\x1d\x2c\x5d\x78\x9e\x12\x7f\x64\x3c\x47\x59\x8f\x48\xb1\xc5\x34\x6c\x79\xc3\xd0\xb6\x8d\xbd\xb0\x56\xaa\x6a\x4e\x3e\xe5\x62\xa5\x27\x10\x60\x60\xe9\xa7\x10\x4a\x77\x49\x48\xac\xd7\x30\x09\xf5\xfd\xf2\x8c\x1c\x12\xeb\x0c\xe2\xb0\xb4\x98\x6c\x2c\x88\x02\x14\xf9\x79\xf1\xa8\x1c\x35\xd6\xa3\xbe\xce\x01\x63\xf8\x5d\xdc\x6f\xfd\x58\xd5\xf7\xba\x12\x20\x5c\xeb\xbc\x7f\x93\xb8\x5a\x9e\x6f\x36\x0e\xbd\x1f\x48\x76\xf2\x32\x20\x84\x3b\x77\x30\x72\x71\x47\xb0\x36\xbe\xd6\x3e\xae\xe9\x68\x9b\x5b\xd9\x83\xaa\xb1\x68\x3f\x0e\x43\xba\x4c\xfd\x1e\x0d\x43\x75\xe0\x65\x98\x5f\xed\x2d\x6e\x62\xb5\xd7\x65\x30\x4f\xfd\x65\xfd\x99\x2f\x53\xb8\x24\x1f\x42\x98\x00\x83\x54\x08\x05\x92\xdc\xbe\x94\x66\xe8\xd9\x8e\x61\x42\xe4\xd5\x62\x4a\x5e\xe6\x65\x4c\x49\x14\x73\x7d\xf2\xa6\x7a\x4c\x3c\x69\xbf\xe6\x49\x1c\x4d\x0d\x13\xb8\x77\xc3\x69\x3d\xb5\xbe\xe9\x50\x57\xb7\x59\xd2\xb0\x86\xda\xd2\xa4\x24\xfe\x19\xb8\x71\x98\x2d\x64\x4e\x43\xa5\x67\x54\xa4\x6c\xed\x3d\xa0\x0f\xc6\xd4\xc4\x13\xaf\x98\x78\x52\x2e\x40\x24\x6e\x2d\x72\x42\x31\xe5\xd9\x0a\x45\xa3\x03\xa4\x86\x9b\xfa\x6b\xaf\x7a\x51\x48\xf4\x85\x9b\xc2\x46\xb2\x92\xdb\xcf\xfc\xdf\x33\xdb\xca\xc4\xaa\x89\xb6\x02\xc7\xad\x15\x2e\xff\x85\xd5\x55\x8e\xd2\xff\x1d\x8b\xab\xf5\xb8\x26\x7d\xaf\x35\x9b\xf8\xbe\xc7\xa8\x5b\x75\x66\x0d\xb4\xc8\x20\x74\x71\xaf\x3b\xfd\x2a\xca\x40\xf7\xfe\x8b\xc4\xd1\x4f\xd1\xe5\x2e\xb6\xe8\x9b\xda\x8d\xde\x77\x22\x73\x64\x78\x94\xd3\x81\x71\xd7\xb7\x7d\xb8\xf7\x5f\xff\x4c\xff\x27\xa9\x38\xdc\xff\x14\x0f\x6d\xa1\x7b\xfc\xf3\xde\x8c\x2f\xc2\xe2\x55\x21\x80\x08\x69\x9e\x9b\x95\xc8\x3f\xd9\xd5\x34\xa1\x8b\xc5\x37\xdf\x0b\x30\xc6\xcd\x98\xd0\x30\x15\x5c\x3b\xf3\xba\x4d\xac\xc7\x68\x45\xfa\x7d\x38\x8a\xec\xe1\xef\xc7\x58\x86\x69\x94\x60\x15\x26\xea\x75\x39\x1a\x6b\x0f\xe3\xe4\x9f\xd1\xcf\x7f\x26\x3f\xff\x19\x49\x47\x63\x57\xa2\xa6\x98\x32\x4d\x7c\x6a\x98\x10\xb4\x76\x21\xc5\xc3\x24\x5e\xa5\x28\x1a\xa2\x61\x2b\xf6\xb6\xa6\x34\xbe\x24\x99\x07\x0f\x60\xe7\x11\x56\xf0\xf3\x64\x5e\x69\x79\x36\xf3\x6f\x41\xef\x64\x3b\x04\x46\x25\x04\xba\x9e\x02\xc1\x4c\x83\x20\x47\x10\xf4\x6f\x8d\xdf\x10\x78\x28\x27\x78\x7f\x01\xa2\xff\x5b\xe6\xdd\x36\xc5\xbf\x1a\xe5\xff\x1b\x16\xbc\xb0\xdd\xd4\x3e\xe6\x5f\x46\xfe\x49\x1b\x6c\x57\x0a\x8f\xb0\x8e\xe7\xda\xde\x9d\x76\x3c\xd7\x41\x63\xa1\x27\xb4\xbf\xa7\x6b\xc8\x3d\x55\x4f\xdb\xf3\xda\xf2\x98\xef\xa0\x17\x42\x25\x94\xa6\x3d\xa8\xaa\x1a\x85\x54\x73\x9b\xd2\xc6\xb3\x56\x37\x33\x81\xcb\xdb\x7c\xcc\xea\xcf\x5b\x1d\xcc\x64\x93\xfa\x71\x43\x19\x14\xd2\x76\x76\xf1\x6b\xd3\xa6\xea\x28\x67\xc3\xcb\xaa\xd5\x68\x93\x94\xfa\x5e\xbf\xb9\x98\xd5\x2a\x59\xed\x67\xeb\x32\xd9\x88\x23\x93\x8d\xc8\x6c\x80\x68\xe6\x3b\x12\x42\xd8\x76\xef\x5b\xed\xae\x84\x8e\xb4\xdc\x62\x4d\x13\xf8\x76\x4f\xda\x7f\xcd\x4f\xb6\xe2\x15\x9b\x28\xaf\xd8\x44\x79\xc5\x9e\x86\x98\x4e\xbe\xf0\x76\x45\x71\xfb\x35\xf8\x35\x6f\x57\xdf\x92\x4e\x9d\xb0\x19\xed\x70\x7b\x9f\xd1\xa4\xdb\x67\xd4\xf3\x30\x58\x22\xd3\x7b\xb2\x68\xee\x49\x9b\x9b\x18\x1d\xf6\xca\x58\x0d\xe9\x7c\xea\x91\xc8\x54\xb5\x20\x67\x92\x0b\x2d\x0d\x13\x96\xcd\xfe\x5a\xa2\x6e\x0b\x27\x6e\xbd\x21\x47\x31\xe1\xe6\xa8\xb1\xae\xe5\x82\xcf\xbc\x16\x12\x85\x1e\x63\x3a\x67\x61\xc5\xa8\x28\xff\xb7\x7f\xb9\xbb\xdd\x7a\x5f\xb6\x8c\x3e\xc0\xec\x6d\x15\x2d\x62\xe1\xa1\x87\x79\x93\x6b\x28\x7f\xe3\x3a\x3b\xac\x44\x0f\x37\xea\x8b\xdc\x3e\xae\xd9\xd7\x24\x70\xda\x41\xc2\xb4\x09\x6e\xd5\x26\x77\x74\xc7\x3d\x57\xa7\x5c\xe1\x7e\x7b\x21\x4c\x3d\x81\x58\xf2\x53\x37\x53\x85\xa9\xf8\xe7\xcd\xd8\x85\xf7\x29\x06\x4b\x79\x8e\xb1\xe0\x83\x47\x06\xcc\xb7\xc8\x40\x15\xe2\x13\x6d\x10\x94\x4d\xfd\xe7\x81\xe6\x55\xda\x73\xf8\xd2\x53\xb5\x92\x76\xbb\x80\xb7\x88\x04\xd6\xc7\x89\xe3\x6d\x2d\x1f\xd6\x0e\x82\xb7\xb5\xbc\x5f\x6d\x79\xd8\xf6\x79\x95\x44\x0e\x0e\xb7\xe8\x43\x08\x1c\x6e\xb1\x43\x88\xc5\xd5\xe7\x67\xd5\x15\x4e\xbd\x4d\x1b\x7f\xab\x5d\x20\xd6\x2e\x9a\x63\xf2\x47\x48\xb8\x07\x2f\x42\x55\xe5\x67\xd7\x53\x69\x11\x92\x42\x15\xa5\x98\x9e\xb5\xa1\x4a\x77\xf7\xb1\x2f\xfb\xc8\x54\x1f\x0f\x80\xda\xd9\xda\x84\xa0\xb5\x8f\x5b\xb8\x00\xc8\x13\x0f\x55\x5e\x2f\x86\xb1\x87\x25\x40\xa3\xd1\x25\x99\x7b\xd0\xe6\x44\xac\xcc\x98\x42\x72\x1e\xf0\x04\x1d\x2b\x0c\xa4\x8c\x50\x49\x1f\x54\x3a\xc7\x7e\x95\xc9\x27\x4f\x3d\x95\xed\xfe\x42\xe8\x03\x5b\xb4\xf9\x42\xe2\xa3\x21\x99\xb0\x8a\x7d\xf2\x75\xe2\xe7\x81\xbf\x52\xa9\x4e\xa5\x5d\xe4\x7c\x2b\xc0\xd6\x8e\x78\x1e\xf6\x8c\xbb\x57\x9e\xea\xef\xc2\x03\x4c\x44\x92\x39\x82\x94\x1b\x98\xf1\xc2\x37\x6c\xe3\x3d\x56\x0a\x34\x6a\x27\x12\x0b\xb1\x8c\xcd\x23\x3c\x1a\x92\x53\xaf\x9c\x5e\x26\x4f\x1a\x3a\x5f\xac\x1e\x8a\xf1\x9a\xd5\x35\xf5\xb9\x5e\xa8\x67\x0a\x18\xd7\x26\x1c\xdf\x40\x36\x4e\x3a\x9e\xeb\x93\x81\x6f\x1d\xcf\xf5\x71\xfa\xb5\xa7\x6a\xcb\x9c\xdd\x72\x09\x93\x78\x55\x5d\xc1\x02\x28\xcf\xf1\x38\x0b\x14\xc8\x4a\xde\xfe\xcd\x83\xd4\x33\x21\xf5\xc8\xb5\x67\x42\x64\x42\xd1\xfa\x40\x15\x42\x50\x2f\xdc\x57\x2f\x1c\xd7\x5e\xe0\x95\x17\xc6\x98\xb4\xa0\xda\xf9\x49\xad\xad\xf6\xcc\xd8\xf3\x5a\xb3\x2a\x60\xa0\x2c\x60\xb9\x97\x53\x59\xef\x85\x43\x20\xae\x96\x80\x15\x47\x2e\xd0\x2a\xd8\x1f\x9d\x11\xe3\xd4\x5f\xe9\xf4\xb9\x62\xa4\xd5\x04\x38\x7c\x48\x31\x4d\x99\x31\xf6\x02\x5e\x3e\x9c\x4e\x64\x5a\x27\x60\xce\x64\x23\x8a\xa1\x69\x9e\x99\x58\x14\x41\xf5\x92\x9c\x79\x40\x2d\xb6\x02\x8a\xa5\x13\xac\x2b\xc4\x62\x6a\xd1\x7e\x15\x6d\x8b\x05\xae\x65\x10\x69\x13\xf7\x8d\x57\xaa\x34\x63\x4f\x87\x69\x96\x82\x5d\xd5\xae\x2f\xf1\xa5\x64\xbb\x3a\x9a\x40\x85\x56\x5b\x46\x9b\x2d\xaf\x46\xdb\x4a\xff\xa2\x1a\x5d\x42\x7e\xae\xcf\xd9\x60\x6b\xb3\x0f\xd2\x39\xf2\xeb\xa6\x69\x0f\x9d\xd8\x0f\x3d\xb2\xf3\xfb\x17\x8a\x3e\x14\x19\xae\x54\x2b\xe5\x91\x14\x07\x83\x61\xc4\xe6\x5f\x7a\xea\x70\xaf\x00\x95\x22\x6f\xcd\x95\xa7\x32\x6f\x17\x90\x92\x7b\x26\xc8\x94\xdb\x2b\x12\x7b\x60\xec\xeb\xfa\x98\xba\xe9\xa4\x68\x1a\xca\xa6\xbb\x66\xeb\xae\x5c\x92\x95\x07\x31\x96\x41\x85\x4b\x72\x2e\xb8\x2d\x05\x56\x4a\xcc\xef\xa4\x60\x35\x7b\x64\x98\xf0\xb6\x8e\x82\x6d\x6a\x48\x55\xa8\x75\xc3\x60\x89\x07\x09\x2e\x27\x43\xc0\xff\x4c\xa3\xe5\xa4\x61\x12\x5c\x96\xf2\x7a\x8d\xc8\xc5\x1e\x0d\x7b\x42\x15\x68\xb3\xd9\xe0\xd3\x81\xd0\xd5\xbc\x24\x5e\x56\x9b\x7d\xad\xc7\x03\x3c\x96\x0e\xa0\x16\x7b\x03\x2a\xef\xe7\x2b\x69\x5d\xb7\xdc\x93\x1b\xc2\x2b\x8a\x09\xe8\xc3\x93\x8e\x63\x84\x8e\xb9\x0f\xbc\x80\x86\xf1\xb4\x57\xbd\x50\xdc\x6a\xcb\x17\xa3\x2e\x8a\xd9\x4c\xba\x1a\x6c\x1a\xe9\xdf\x79\xf5\xe7\x2a\x71\x47\x9d\x96\xd7\x48\xb9\x1b\xc6\xa9\x3a\x78\x4e\x5a\x1d\x19\xda\x96\x3a\xf6\xae\x74\xa7\xbc\xbd\xc9\x24\x8e\x2b\x9c\xd8\xaf\x3a\xfd\xdd\xb4\x77\x6a\x85\x0b\x21\x0b\x0e\xb6\x89\x41\x55\x29\xe8\xa8\xb3\x21\x7b\x83\x6c\x7b\x37\xf1\x7b\x57\x71\xd6\x4b\x33\xf5\x63\x45\x23\xde\xe3\x71\x4f\x96\xbf\xad\x51\x8f\x91\x58\x94\x57\xad\x81\xd6\x35\x56\x79\x49\xc9\x9c\x1c\x78\xb2\x72\x58\xd5\x8b\x32\x8e\x26\x41\xb2\x90\x24\x84\x3e\xb6\x2f\x29\x71\x53\x13\xdc\x13\xdb\x18\xcb\xd1\x34\xd5\x15\x53\xff\xbe\x45\xf7\x69\xd3\x6a\x7b\x37\x46\xd1\x46\x98\x81\xe0\x38\x2c\xeb\xf9\xbc\xde\xb2\x8e\x35\x09\xf5\x43\xa7\xe2\x24\x13\x78\x5c\x6e\x46\x37\xb7\x6a\x1b\x37\x3b\xd2\x6c\x04\xa9\xe3\x4a\xbe\x6e\xae\xa4\x5c\x2e\xa3\x66\x78\xfa\xab\xc7\x38\xf0\x43\x9f\xab\x20\xf3\xb5\x09\x2f\x3a\xb7\x23\xcc\x49\x64\xde\x35\xfe\xae\xea\x10\xcb\xa4\x2a\x98\x40\xfd\x95\xd7\xe2\x76\x5e\xcd\x4f\x5a\x4b\xf8\x8c\xa5\x87\x0c\xdf\x0b\x38\x66\x2b\xe5\xce\x2f\xfa\x06\x57\x91\x55\xf0\x70\xa3\xea\xbd\xa3\xb6\x69\xc4\xed\x5f\xec\x75\x4e\x5e\x78\x80\xae\xf2\x58\xe1\xa8\x7e\x86\x2e\x45\x49\x89\x93\xcf\x3b\x4c\xbb\xef\x33\x19\x77\x60\x38\xff\xcb\xb0\x4b\x53\xc9\x43\x0c\x42\xc0\x37\xdf\xb7\x2d\xd3\x25\x25\x61\xba\x99\xa3\xa8\xb5\xd6\x71\xcd\x17\xc1\xf3\xa4\xab\x06\x3c\xf7\xa4\x1d\xf9\xf3\x16\x34\xfa\xcf\x0c\x58\x2e\x26\x5b\x51\x8d\xab\x38\x56\x41\xa7\xef\x1e\x0a\x8d\x29\x26\xde\x1f\x6f\x2a\xc2\xf2\x39\xca\xac\xd8\x82\xad\x5a\xb0\x05\xbb\x50\xa5\xbe\x65\x2f\x98\x33\x8f\xa0\x01\xe4\xc3\xaf\xfa\xa7\xd7\xb3\xd8\x54\x65\xff\x0f\x81\x8f\x24\xdc\x14\x68\x81\x99\x41\xc8\x07\x0f\x12\x59\x0c\xb6\xce\x01\x4a\x33\xce\x7b\x4f\x4c\xa9\x6f\x0a\xf9\x82\x44\xa3\x53\x4e\xe6\xe4\x48\xbd\x65\xda\x17\xbc\x34\x1d\xae\x4d\x78\xd3\x0a\x80\x69\x42\x56\x09\x82\x82\x8a\xe6\xfd\x58\xd3\x01\x12\xa8\x96\xad\xe2\x1b\x56\x20\xf4\xe0\x28\x82\xf8\xa5\x4f\x46\x7f\x8b\x8b\x01\x9d\xad\xa5\xe7\xcd\x56\x97\x1a\xb6\xb7\x56\xae\x34\x58\x82\xd7\x04\xe9\x8f\xa5\x82\x0c\xf5\xfa\xe9\x63\x4e\x7b\x4e\xde\x14\x3c\xbc\x84\xbd\x72\x91\xda\x23\x70\xe4\xe6\x7d\xf6\x74\x70\x77\x84\xf5\xf2\x65\xc8\x4f\xd6\x66\x33\xe1\xed\x36\x13\x54\x2a\xd6\x26\x7c\xf2\xaa\x25\x01\xbe\xd4\xd7\x7a\x23\xc7\x85\x86\x50\xed\x92\x5e\x1f\xac\x28\x12\xbf\x31\x5a\x51\x71\x7e\xbd\x86\x97\x1d\x1a\x9d\xf6\xf5\x8a\xfa\xdd\x8a\x1c\xfa\x0f\x70\x88\xe4\x0e\xbc\xf4\xe0\x92\x9a\xd5\x1a\xcf\xc1\x84\x24\xba\x26\x57\xf2\xac\x38\xc5\x52\x09\xfa\xbe\x78\xda\x35\xa9\x62\x36\xa7\xde\xd4\xef\xe1\xbf\x83\x65\x10\x86\xf1\x4a\x5d\xa8\x0f\x50\xb8\x8c\xbc\x98\xc7\xcb\xde\xa2\x1e\x35\x20\x8f\xb4\x50\xd4\x59\x77\x0c\xf7\xd5\xc4\x9a\xd1\x26\x24\xfd\x2a\xb9\x4a\x54\xa4\xec\x03\x25\x4b\xff\x68\x31\x93\x77\x78\x61\x14\x84\xa8\x3b\x2c\x2c\xea\x63\xc9\x44\xf6\x59\xfc\xb3\x87\x71\xd5\xc5\x04\x6f\xd9\xef\x5c\x76\x32\x14\xf0\x81\xf3\xe7\x7d\x0c\x10\x9b\xf1\x45\x78\x18\x27\x86\x09\x7e\xdf\xf1\x12\xc8\xfa\x4e\x3f\x01\xda\xff\x0f\x96\xc6\x76\xa9\x4a\x23\xf6\x01\xd4\xa1\x0c\x5f\x9b\xed\xd2\x59\x41\x72\xdc\xce\x0f\x52\xa0\xaa\xe5\xa7\xa0\xd9\xf0\xbf\x43\x7e\xda\x15\xdf\xee\xf6\xff\xad\xf2\x53\xd7\x18\x1b\xf2\x53\xdc\x97\xa9\x28\x0d\x13\x26\x5d\xab\xd6\x6b\x1c\xbd\xc9\x83\xc1\x2d\x0a\xfa\x7d\x74\x0a\xc7\xb6\xb5\x8c\x01\x73\x12\xf7\xdb\x0e\x0b\xeb\x26\xc3\x9d\xe1\xcd\x36\xc3\xa4\xd0\x77\x59\xbf\xdb\xec\xd2\x99\x36\x60\x17\x33\x8d\xdf\x2f\xd3\x06\x2c\x15\x28\xde\x60\x4a\x29\xe3\xb5\x60\x23\x57\x40\xe1\xa0\xf5\xca\x93\xe9\xcb\x82\x3e\x70\xc5\x47\xe5\x47\x4e\xfa\x60\x1c\x1f\x18\xf0\x1c\xa9\xfa\x87\xe2\x9e\x14\x05\x7a\x94\xe3\xa3\xe3\x10\x0b\xef\x99\xc5\x63\x21\x49\xd4\x1e\xd2\x71\xf9\x50\x5a\x0b\xbd\xfa\xcb\x07\xe5\x73\x69\x56\xf4\x7a\xec\x4a\x8f\xbb\x5f\x3e\xd3\x16\x08\xf9\x60\xb7\x3a\x21\xee\xe3\x6d\x41\x07\x15\x26\x14\x4f\xb5\xcd\xc7\xa8\x9d\x11\x21\x55\x7f\xee\xa9\xb3\x22\x53\x95\xd3\x33\x21\x13\x32\x82\x2f\x65\x04\x8a\x2b\x32\x2c\x64\x84\xb5\x09\x69\xbf\x5d\x3c\x4d\xc2\xa6\x6e\x5f\x03\xa2\x16\x2b\xd3\x29\x5d\xf8\xb6\xb2\x44\xc9\x3c\x68\x0f\xdb\x85\x98\x2d\x7d\xec\xca\x4a\x12\xf5\x6e\xa2\x32\xca\x57\xa2\xcb\xec\xbe\x61\x42\xde\x6f\xca\xc7\xd2\x6e\xa1\x4a\xb8\x5f\x49\x9b\xc5\x93\x67\x55\x05\x51\x7d\x55\x58\xa2\x81\xb1\x2f\x4b\x29\xf4\xce\x65\x4d\x04\x1c\xb8\xce\x18\x79\x23\x3f\x8d\xe4\x93\xbc\xfd\x58\xa8\x0b\x47\xcb\x4f\x16\x58\x96\x2e\xea\x41\x74\xb8\x7c\x46\x2b\x42\xa6\x8b\xc1\xce\xb0\x25\xf0\x5e\x88\xa4\x7f\x7e\x60\xf9\xdd\xb7\x19\x5a\xa3\x1c\x49\x84\xd4\x73\xa6\x44\x00\x43\xc0\x14\x34\xe5\x73\xbf\x59\xf1\x46\xbe\x50\x46\x61\xdc\x19\x6e\x12\xf3\xa2\x8d\x3e\x4f\xc3\x36\x8d\x44\xe8\xaa\x91\x32\xa9\x63\x5c\xf5\x9a\x88\x59\x7e\x12\xda\x91\x50\x25\x7b\x86\x44\x8c\x3d\x2a\x7d\xb9\x5f\x05\xd2\x41\xbb\xfc\xf0\x2d\xa2\x9a\x9e\xb2\xaa\xc0\x52\x9f\x63\x59\x7d\x65\x53\x54\x2b\xc2\xc3\xd7\x6b\xe2\x57\x2d\x39\x75\x70\xca\x3a\xc0\x29\xfb\x2b\xc1\xe9\xb5\xef\x27\xe5\xa6\x1e\x85\xed\x9b\x2a\x03\xa6\xfb\x10\x69\x78\x42\x34\xf3\x24\x9a\xb9\xb1\x87\xc9\x6c\xe5\xd5\x52\xb0\x46\x58\x74\x10\x8c\x0e\x6a\x5d\x41\xa9\x3f\xff\x49\xef\xb1\x4e\xcb\x2d\x71\x64\xc1\x84\x10\x31\x2e\xb6\x20\xef\x0b\x52\x72\x25\x23\x41\x2c\x76\x04\x5d\xe4\x40\x95\x75\xe9\x1d\x47\xb2\x52\xb3\xca\x79\xf1\x57\x7c\xc0\x1e\xd6\x7d\xb9\xe5\x07\x70\x8b\xf2\x36\x0e\xfd\x2f\x0e\xad\x4b\xd3\xdc\x7e\xf4\xec\x2f\x1e\xfd\x7d\xea\x27\xb7\x1f\x3d\xff\xeb\x46\x7f\xae\x4b\xf5\xdc\x7e\xf4\xb7\x7f\xdd\xe8\x6f\x55\x6d\x9f\x5b\x0f\xce\x5a\x5d\xab\xff\xb5\xc1\x7f\xf5\xc3\xd9\xf3\x92\x6a\x61\x4c\x64\x64\xd1\x3d\x8b\xfe\x56\x73\xc4\xae\x31\x4f\x59\x2a\x49\x75\xdf\x2f\x26\xb3\xac\xc4\x10\xd4\x92\x8f\xff\x6d\xf2\xdb\xe4\xb7\xc9\xd3\x5a\xe2\xf1\xc1\x84\x2e\x82\xf0\xca\x00\x63\x11\x47\xb1\x4c\xf0\x54\x7c\xa0\xd7\x6f\x78\xb4\xaa\x40\xa9\x67\x8a\xe7\xaf\x61\xd6\x2a\x0b\xe8\xc0\x01\x27\xb2\xdc\xeb\xa6\xf7\xe3\xe3\x52\xb8\x7f\x99\xc2\xa2\x0f\x52\xe9\xb8\xde\x2c\xd3\xdc\x96\x23\x83\xa5\x52\xd4\x58\xca\x03\x92\x0b\x14\x35\xd8\xf7\x67\x1d\x7e\x33\xb4\xea\x41\xb2\x4b\x58\x1f\x7c\xe0\x40\xe1\xce\x9d\xac\x70\xe4\xe8\x74\x41\xa9\x3b\x70\xac\xd7\x24\xb2\xdc\x71\xd3\xff\xe3\x4b\x2e\x3e\xe0\x04\xdc\x22\x29\x7e\x91\x14\x93\x3b\xb8\x93\xee\x81\x69\xd1\x63\x99\x83\x71\x0f\x30\xc5\xee\x4c\x66\xd8\xfd\x0e\x9d\xd9\xb2\x1e\xb6\xe9\x18\xca\xa7\x8c\xf7\xdb\xb3\x60\x7c\x6d\x8d\x60\x28\x3d\xfd\xc3\x14\xad\x0f\x57\xb9\xca\x1f\x0b\x97\xc4\xef\x43\xd2\x47\x57\x56\xd8\x25\x59\x1f\x3e\x7a\x40\xf1\xf2\x6b\xa3\x2c\x9e\xec\x87\xc2\x2e\xd9\xf3\xe0\x82\x8b\x0f\x16\x5f\xfe\x0d\x22\xcb\xdd\x6f\xd8\x70\x6a\xad\x4f\x39\x11\xcb\x03\x1f\xb0\xee\x45\xb5\xfd\x6f\xdd\x0b\x1f\x79\xeb\x35\x2c\xfb\xce\x8f\x3d\xbb\xac\xd2\x03\xf4\xa1\xad\xce\x55\x8d\x35\x4c\xf5\xd3\xd2\x6e\x2d\x9e\x9f\xeb\xab\x35\xac\x8a\x16\xaa\xc6\x19\x3e\x97\xbf\xd7\x70\xd5\x17\x02\xd5\xb2\x0f\xd3\x3e\xac\xfa\x20\x5a\xea\x5c\xd2\xcb\x24\x5e\xf8\x7c\xe6\x67\xa9\x15\xc4\xf7\xbc\xd8\x4d\xe5\x14\x82\x68\x2a\x7f\x2c\x68\x44\xa7\x7e\x72\x4f\x76\x79\xe4\x87\x4b\x63\x2d\x38\xbb\x1c\x50\xde\x35\xd6\x70\xd9\xa9\x5e\x1e\xb6\x4a\x42\xcd\x82\x85\xcb\xfe\xa6\xe2\xdd\xd7\x6b\xad\x36\x48\x41\x5d\x1d\x7d\xa6\xfd\x8d\x14\xac\xab\x7e\x43\xbb\xee\x0b\xa8\x36\x21\x31\x47\x46\xaf\x4c\xd8\xb0\x36\x61\x77\x8b\x52\xdc\x92\x86\xeb\xee\x9c\x5c\x2a\x9d\x5b\x03\x6d\x58\x6b\xa5\xaa\x13\xcc\x42\x92\x58\x7b\x98\x61\x4f\x05\x12\x42\x3d\xac\x50\x6a\x47\x63\xa5\x6e\xa8\xc3\x43\xd8\x97\xd7\x11\xcd\x0d\x13\x0e\x3b\x24\xa1\x71\xbf\x32\x20\x13\x82\x1d\xfe\x19\xf0\x78\x3a\x0d\x7d\x21\x1f\x0e\x16\x9e\xbe\x19\x06\xd3\x19\x2f\xdd\x37\x17\x6c\xf0\xa8\xb7\xe4\x83\x07\xbd\xa5\x0c\x5d\xa9\x25\x1b\x64\x31\xe7\xf1\xc2\x00\x63\x67\x79\xd9\x4b\xe3\x30\xf0\x7a\xc9\x94\x51\x32\x84\x9e\xfc\xdf\xda\xb9\xff\xc8\x2c\xf1\x75\xbf\xc2\x1a\x22\x4e\x83\xa8\x7a\x02\x5a\x5b\x17\x31\x15\x96\xd0\xc8\xd3\xf6\xea\x86\xf7\x80\x82\xb2\xa6\x3c\xa9\xde\xc6\x35\xf9\x2a\x59\x86\x94\x2a\x77\xfb\x24\x31\xe1\x0a\xb5\xd0\xa6\x72\x50\xad\x8e\xda\xea\xde\xd6\x30\xc0\x6c\xb0\xc2\x20\x0a\x83\xc8\x2f\x43\x2a\x9b\xdf\xd5\x11\xd4\xbe\x61\x8f\x8f\xfc\x55\x4d\x0b\xab\xb8\x80\x14\x5e\xcc\xa4\xea\x9c\x93\xac\xe1\x74\xbb\xa9\xa6\x46\x46\xd5\x39\x0a\xf5\xd0\xb8\x0b\xc6\x43\x8c\xdc\xd6\xc1\x98\x2a\x7d\x64\xd2\x74\xbf\x85\x43\x21\xb0\xba\xd7\x9b\x5c\x5b\x6d\xa4\x00\x90\x82\x34\xcf\xfa\xa4\x92\x7f\xe5\xa2\x0d\x30\x7f\xf4\xed\x1d\x9d\x80\xe5\xbc\xab\x81\xf6\xc9\x3e\x6e\x05\x6d\x56\x9c\x19\xc0\x49\xdf\x99\x26\xc4\x48\x30\x95\xdf\xb7\xce\xd5\xb8\x24\xc7\x7d\x30\x10\xe7\x40\xe6\x3e\x8f\x4c\x38\xe9\x13\x23\xe5\x57\xa1\x9f\xce\x7c\x5f\x7a\x45\x67\x21\x18\x61\x4c\x3d\x99\x6e\x81\xcc\x31\x43\x98\xa9\x9f\xf8\x49\x12\x27\xea\xd1\x55\x40\x8c\x43\x1a\x84\xbe\xd7\xe3\x71\x4f\xbc\xd3\xdb\x3f\x3f\xef\x4d\x92\x78\x21\x2b\x58\x9a\x2a\x41\xc3\xda\x84\xeb\xca\x57\xb4\xed\x10\x89\x9c\xc4\x72\xc3\x1a\xeb\xfb\xd6\x87\xe8\xae\x11\x06\xec\x1e\x8b\x63\x9e\xf2\x84\x2e\x07\x0f\xad\xa1\x35\x1c\xd0\x70\x39\xa3\xd6\xe3\x81\x17\xa4\xfc\x9e\x9b\xa6\x65\x03\x6b\x11\x44\x96\x2b\xd4\xd9\x0b\x74\xb8\x28\xfb\x40\xd9\x86\xae\xfc\x34\x5e\xf8\x83\x87\xd6\x6f\xd6\x10\xdf\xac\xde\x2e\x5f\x3e\xef\x4b\xa1\xab\x82\x2b\x52\x2d\x3c\x23\x89\xc5\xde\x42\x62\xb9\xcc\x7c\x56\x56\x10\x48\xf4\xaf\x02\xa3\x68\x45\xea\x28\xed\xa8\x2d\x85\x9d\x8b\x0f\x3e\xec\x93\xe4\xf6\x30\xa6\xc5\x2f\x4d\xf5\x59\xe2\xd3\x79\x2f\x2a\x50\x55\x5e\x27\xeb\x4d\x06\x7c\x2a\x2d\xea\xb4\x7a\x94\x12\x4c\x88\xcc\x0b\x28\xe6\xa7\x3b\xd2\x1d\xd4\x28\xc1\x7a\xb3\x1f\xcc\x66\x45\x0a\x7c\x8c\xd6\x70\x56\xdf\x69\x75\x88\x61\xb9\x29\xb8\xe2\x0f\x07\x5e\xad\x99\xc5\x2d\x4a\x22\xf2\x29\x21\xa6\x69\xae\xb5\x50\xf6\x39\x21\x3f\x5e\xd9\x45\xab\xa2\x8c\x68\x8f\x5b\xd4\xa1\x10\x71\x8b\x7a\xde\x38\xf7\x23\x7e\x12\xa4\xdc\x8f\x7c\xa1\x11\xc7\xcb\x54\x9a\xea\xb8\x29\x5a\x44\x34\x0f\xa6\x94\xc7\x89\x95\xa5\x7e\xb2\x3b\xf5\x23\x6e\x05\x91\xe7\x5f\x9e\x4d\x88\xf1\x2e\x09\x3c\x74\x51\xf9\x7d\xf8\xf3\x67\x6b\x77\x33\x9a\xce\x74\x36\x4a\xde\xac\x3e\x11\x4c\xc8\x1d\xb1\x5b\x3c\x09\x5f\xfa\x57\x3f\x7f\x26\xd6\xc2\xe7\x54\xfd\x4c\x67\xc1\x84\xe3\xef\x9d\xdf\x85\x40\x87\xa5\x8d\x7e\xfe\x8c\x2c\x99\x32\x4e\xfc\xf2\xe2\x55\x24\x10\xc6\x34\x7f\x24\xd6\x32\xf1\xc5\xe0\x07\x72\x37\x48\x19\x69\x30\x4b\xfc\x09\xf8\x8e\x58\x1d\xc8\x9c\x8b\x98\x70\xd3\xa2\xcf\x28\x71\x49\xf6\xf7\xbf\xfb\x16\xf3\x1d\xc7\xc9\x2c\xe6\x8b\x0b\xfa\x1e\x2f\xe8\x7b\x7c\x42\x2d\x2a\x9f\x51\x8b\x8e\x94\xa7\x44\xb6\xb6\x95\xef\x09\x5f\xa3\xc1\x7b\x0d\xee\xd4\x6e\x3d\x76\x49\x2c\x77\x0a\x11\xe0\xc0\x5c\xb4\x7b\x63\x27\x96\xfb\x06\xdc\x33\xf1\xf7\x0c\xdc\x23\xf1\xf7\x48\x74\xb1\xd7\x77\xbe\x44\xa4\x6f\xc2\xbb\x4e\xca\xa3\xdc\xac\x46\x89\x8d\x45\x0c\x30\xdf\xbd\xac\x5e\xfc\x76\xcb\x19\x99\xaa\x9f\x35\xe2\xf6\x11\xe1\x70\x24\x9e\x5a\x54\xa6\x6a\xee\x3b\x67\x7d\xf2\xc3\x9d\xda\xaf\x53\x70\x53\xfb\x8a\x82\xcb\xed\x86\x66\x50\xfa\x15\xf4\x47\xda\x35\x37\xb2\xe8\xda\x96\x9a\x14\x68\x7f\xe4\x4b\xf2\xb6\x0f\xc6\xdf\xf0\x68\xf9\x0c\xe4\xd5\x48\x5c\xb9\x39\xa6\x04\x79\xd7\x87\xc4\x62\x14\x8e\x04\xea\xfb\xa3\xb2\xb0\x88\x5d\x56\x1b\x49\x2c\xfa\xde\xc4\xb4\xae\x13\xf4\xaf\x5d\x8b\x25\x3a\xf4\xc9\x5e\xdf\x14\x8b\x76\x96\x8a\x25\x6c\xa1\xf3\xec\x8d\x3d\x26\x7f\x5c\x4b\x96\x81\x07\x39\x35\x06\xbf\x5e\xaf\xcd\x67\x67\x81\xf3\xe3\x15\x0d\x22\xfb\x47\x10\x05\xdc\x3e\xe8\x93\xb9\x6b\x92\xa1\xb9\x5e\x43\x64\x8d\xc3\xc5\x48\xf7\xdb\x8b\x30\x59\x31\xe6\x9a\xc2\xa3\xe1\x5e\x10\xf5\xb8\x89\x7f\x92\x11\x66\x4d\x36\x1c\xc7\x1f\xed\x93\xc7\xa6\x1d\x91\xe4\x0f\xff\x2b\xf0\x3f\xfc\xaf\xa6\x2d\x7e\x3a\xe2\xa7\xd0\x67\xc6\xe1\x02\xce\x02\xd3\xc6\x5f\xce\x59\xb0\x26\x7c\x16\xa4\xe6\xb3\xff\x1b\x00\x00\xff\xff\x86\x75\x45\xdf\xa4\x82\x01\x00"), }, "/templates": &vfsgenÛ°DirInfo{ name: "templates", diff --git a/vendor/github.com/prometheus/alertmanager/cluster/cluster.go b/vendor/github.com/prometheus/alertmanager/cluster/cluster.go index 20c7a1c3a15..322481ea833 100644 --- a/vendor/github.com/prometheus/alertmanager/cluster/cluster.go +++ b/vendor/github.com/prometheus/alertmanager/cluster/cluster.go @@ -121,11 +121,11 @@ func Create( ) (*Peer, error) { bindHost, bindPortStr, err := net.SplitHostPort(bindAddr) if err != nil { - return nil, err + return nil, errors.Wrap(err, "invalid listen address") } bindPort, err := strconv.Atoi(bindPortStr) if err != nil { - return nil, errors.Wrap(err, "invalid listen address") + return nil, errors.Wrapf(err, "address %s: invalid port", bindAddr) } var advertiseHost string @@ -138,7 +138,7 @@ func Create( } advertisePort, err = strconv.Atoi(advertisePortStr) if err != nil { - return nil, errors.Wrap(err, "invalid advertise address, wrong port") + return nil, errors.Wrapf(err, "address %s: invalid port", advertiseAddr) } } @@ -260,8 +260,8 @@ func (p *Peer) setInitialFailed(peers []string, myAddr string) { return } - p.peerLock.RLock() - defer p.peerLock.RUnlock() + p.peerLock.Lock() + defer p.peerLock.Unlock() now := time.Now() for _, peerAddr := range peers { diff --git a/vendor/github.com/prometheus/alertmanager/config/config.go b/vendor/github.com/prometheus/alertmanager/config/config.go index d6ad565d00e..5294e4da77f 100644 --- a/vendor/github.com/prometheus/alertmanager/config/config.go +++ b/vendor/github.com/prometheus/alertmanager/config/config.go @@ -516,6 +516,28 @@ func (hp *HostPort) UnmarshalYAML(unmarshal func(interface{}) error) error { return nil } +// UnmarshalJSON implements the json.Unmarshaler interface for HostPort. +func (hp *HostPort) UnmarshalJSON(data []byte) error { + var ( + s string + err error + ) + if err = json.Unmarshal(data, &s); err != nil { + return err + } + if s == "" { + return nil + } + hp.Host, hp.Port, err = net.SplitHostPort(s) + if err != nil { + return err + } + if hp.Port == "" { + return errors.Errorf("address %q: port cannot be empty", s) + } + return nil +} + // MarshalYAML implements the yaml.Marshaler interface for HostPort. func (hp HostPort) MarshalYAML() (interface{}, error) { return hp.String(), nil @@ -579,7 +601,7 @@ type Route struct { GroupByAll bool `yaml:"-" json:"-"` Match map[string]string `yaml:"match,omitempty" json:"match,omitempty"` - MatchRE map[string]Regexp `yaml:"match_re,omitempty" json:"match_re,omitempty"` + MatchRE MatchRegexps `yaml:"match_re,omitempty" json:"match_re,omitempty"` Continue bool `yaml:"continue,omitempty" json:"continue,omitempty"` Routes []*Route `yaml:"routes,omitempty" json:"routes,omitempty"` @@ -601,11 +623,6 @@ func (r *Route) UnmarshalYAML(unmarshal func(interface{}) error) error { } } - for k := range r.MatchRE { - if !model.LabelNameRE.MatchString(k) { - return fmt.Errorf("invalid label name %q", k) - } - } for _, l := range r.GroupByStr { if l == "..." { r.GroupByAll = true @@ -650,13 +667,13 @@ type InhibitRule struct { SourceMatch map[string]string `yaml:"source_match,omitempty" json:"source_match,omitempty"` // SourceMatchRE defines pairs like SourceMatch but does regular expression // matching. - SourceMatchRE map[string]Regexp `yaml:"source_match_re,omitempty" json:"source_match_re,omitempty"` + SourceMatchRE MatchRegexps `yaml:"source_match_re,omitempty" json:"source_match_re,omitempty"` // TargetMatch defines a set of labels that have to equal the given // value for target alerts. TargetMatch map[string]string `yaml:"target_match,omitempty" json:"target_match,omitempty"` // TargetMatchRE defines pairs like TargetMatch but does regular expression // matching. - TargetMatchRE map[string]Regexp `yaml:"target_match_re,omitempty" json:"target_match_re,omitempty"` + TargetMatchRE MatchRegexps `yaml:"target_match_re,omitempty" json:"target_match_re,omitempty"` // A set of labels that must be equal between the source and target alert // for them to be a match. Equal model.LabelNames `yaml:"equal,omitempty" json:"equal,omitempty"` @@ -675,24 +692,12 @@ func (r *InhibitRule) UnmarshalYAML(unmarshal func(interface{}) error) error { } } - for k := range r.SourceMatchRE { - if !model.LabelNameRE.MatchString(k) { - return fmt.Errorf("invalid label name %q", k) - } - } - for k := range r.TargetMatch { if !model.LabelNameRE.MatchString(k) { return fmt.Errorf("invalid label name %q", k) } } - for k := range r.TargetMatchRE { - if !model.LabelNameRE.MatchString(k) { - return fmt.Errorf("invalid label name %q", k) - } - } - return nil } @@ -724,6 +729,26 @@ func (c *Receiver) UnmarshalYAML(unmarshal func(interface{}) error) error { return nil } +// MatchRegexps represents a map of Regexp. +type MatchRegexps map[string]Regexp + +// UnmarshalYAML implements the yaml.Unmarshaler interface for MatchRegexps. +func (m *MatchRegexps) UnmarshalYAML(unmarshal func(interface{}) error) error { + type plain MatchRegexps + if err := unmarshal((*plain)(m)); err != nil { + return err + } + for k, v := range *m { + if !model.LabelNameRE.MatchString(k) { + return fmt.Errorf("invalid label name %q", k) + } + if v.Regexp == nil { + return fmt.Errorf("invalid regexp value for %q", k) + } + } + return nil +} + // Regexp encapsulates a regexp.Regexp and makes it YAML marshalable. type Regexp struct { *regexp.Regexp diff --git a/vendor/github.com/prometheus/alertmanager/config/notifiers.go b/vendor/github.com/prometheus/alertmanager/config/notifiers.go index 16416eb142a..82829ded36d 100644 --- a/vendor/github.com/prometheus/alertmanager/config/notifiers.go +++ b/vendor/github.com/prometheus/alertmanager/config/notifiers.go @@ -217,7 +217,7 @@ type PagerdutyConfig struct { // PagerdutyLink is a link type PagerdutyLink struct { - HRef string `yaml:"href,omitempty" json:"href,omitempty"` + Href string `yaml:"href,omitempty" json:"href,omitempty"` Text string `yaml:"text,omitempty" json:"text,omitempty"` } diff --git a/vendor/github.com/prometheus/alertmanager/dispatch/dispatch.go b/vendor/github.com/prometheus/alertmanager/dispatch/dispatch.go index 24a390aed1e..a024866d4f5 100644 --- a/vendor/github.com/prometheus/alertmanager/dispatch/dispatch.go +++ b/vendor/github.com/prometheus/alertmanager/dispatch/dispatch.go @@ -22,6 +22,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" "github.com/prometheus/alertmanager/notify" @@ -30,12 +31,39 @@ import ( "github.com/prometheus/alertmanager/types" ) +// DispatcherMetrics represents metrics associated to a dispatcher. +type DispatcherMetrics struct { + aggrGroups prometheus.Gauge + processingDuration prometheus.Summary +} + +// NewDispatcherMetrics returns a new registered DispatchMetrics. +func NewDispatcherMetrics(r prometheus.Registerer) *DispatcherMetrics { + m := DispatcherMetrics{ + aggrGroups: prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "alertmanager_dispatcher_aggregation_groups", + Help: "Number of active aggregation groups", + }, + ), + processingDuration: prometheus.NewSummary( + prometheus.SummaryOpts{ + Name: "alertmanager_dispatcher_alert_processing_duration_seconds", + Help: "Summary of latencies for the processing of alerts.", + }, + ), + } + prometheus.MustRegister(m.aggrGroups, m.processingDuration) + return &m +} + // Dispatcher sorts incoming alerts into aggregation groups and // assigns the correct notifiers to each. type Dispatcher struct { - route *Route - alerts provider.Alerts - stage notify.Stage + route *Route + alerts provider.Alerts + stage notify.Stage + metrics *DispatcherMetrics marker types.Marker timeout func(time.Duration) time.Duration @@ -58,6 +86,7 @@ func NewDispatcher( mk types.Marker, to func(time.Duration) time.Duration, l log.Logger, + m *DispatcherMetrics, ) *Dispatcher { disp := &Dispatcher{ alerts: ap, @@ -66,6 +95,7 @@ func NewDispatcher( marker: mk, timeout: to, logger: log.With(l, "component", "dispatcher"), + metrics: m, } return disp } @@ -76,6 +106,7 @@ func (d *Dispatcher) Run() { d.mtx.Lock() d.aggrGroups = map[*Route]map[model.Fingerprint]*aggrGroup{} + d.metrics.aggrGroups.Set(0) d.mtx.Unlock() d.ctx, d.cancel = context.WithCancel(context.Background()) @@ -109,9 +140,11 @@ func (d *Dispatcher) run(it provider.AlertIterator) { continue } + now := time.Now() for _, r := range d.route.Match(alert.Labels) { d.processAlert(alert, r) } + d.metrics.processingDuration.Observe(time.Since(now).Seconds()) case <-cleanup.C: d.mtx.Lock() @@ -121,6 +154,7 @@ func (d *Dispatcher) run(it provider.AlertIterator) { if ag.empty() { ag.stop() delete(groups, ag.fingerprint()) + d.metrics.aggrGroups.Dec() } } } @@ -252,6 +286,7 @@ func (d *Dispatcher) processAlert(alert *types.Alert, route *Route) { if !ok { ag = newAggrGroup(d.ctx, groupLabels, route, d.timeout, d.logger) group[fp] = ag + d.metrics.aggrGroups.Inc() go ag.run(func(ctx context.Context, alerts ...*types.Alert) bool { _, _, err := d.stage.Exec(ctx, d.logger, alerts...) @@ -313,12 +348,10 @@ func newAggrGroup(ctx context.Context, labels model.LabelSet, r *Route, to func( routeKey: r.Key(), opts: &r.RouteOpts, timeout: to, - alerts: store.NewAlerts(15 * time.Minute), + alerts: store.NewAlerts(), done: make(chan struct{}), } - ag.ctx, ag.cancel = context.WithCancel(ctx) - ag.alerts.Run(ag.ctx) ag.logger = log.With(logger, "aggrGroup", ag) @@ -438,14 +471,13 @@ func (ag *aggrGroup) flush(notify func(...*types.Alert) bool) { fp := a.Fingerprint() got, err := ag.alerts.Get(fp) if err != nil { - // This should only happen if the Alert was - // deleted from the store during the flush. - level.Error(ag.logger).Log("msg", "failed to get alert", "err", err) + // This should never happen. + level.Error(ag.logger).Log("msg", "failed to get alert", "err", err, "alert", a.String()) continue } if a.Resolved() && got.UpdatedAt == a.UpdatedAt { if err := ag.alerts.Delete(fp); err != nil { - level.Error(ag.logger).Log("msg", "error on delete alert", "err", err) + level.Error(ag.logger).Log("msg", "error on delete alert", "err", err, "alert", a.String()) } } } diff --git a/vendor/github.com/prometheus/alertmanager/inhibit/inhibit.go b/vendor/github.com/prometheus/alertmanager/inhibit/inhibit.go index b4d00fd299e..043fe8a23c1 100644 --- a/vendor/github.com/prometheus/alertmanager/inhibit/inhibit.go +++ b/vendor/github.com/prometheus/alertmanager/inhibit/inhibit.go @@ -94,7 +94,7 @@ func (ih *Inhibitor) Run() { runCtx, runCancel := context.WithCancel(ctx) for _, rule := range ih.rules { - rule.scache.Run(runCtx) + go rule.scache.Run(runCtx, 15*time.Minute) } g.Add(func() error { @@ -194,7 +194,7 @@ func NewInhibitRule(cr *config.InhibitRule) *InhibitRule { SourceMatchers: sourcem, TargetMatchers: targetm, Equal: equal, - scache: store.NewAlerts(15 * time.Minute), + scache: store.NewAlerts(), } } diff --git a/vendor/github.com/prometheus/alertmanager/nflog/nflog.go b/vendor/github.com/prometheus/alertmanager/nflog/nflog.go index cdc2bc509e6..635588cb065 100644 --- a/vendor/github.com/prometheus/alertmanager/nflog/nflog.go +++ b/vendor/github.com/prometheus/alertmanager/nflog/nflog.go @@ -39,7 +39,7 @@ import ( var ErrNotFound = errors.New("not found") // ErrInvalidState is returned if the state isn't valid. -var ErrInvalidState = fmt.Errorf("invalid state") +var ErrInvalidState = errors.New("invalid state") // query currently allows filtering by and/or receiver group key. // It is configured via QueryParameter functions. @@ -193,7 +193,7 @@ func WithMetrics(r prometheus.Registerer) Option { func WithMaintenance(d time.Duration, stopc chan struct{}, done func()) Option { return func(l *Log) error { if d == 0 { - return fmt.Errorf("maintenance interval must not be 0") + return errors.New("maintenance interval must not be 0") } l.runInterval = d l.stopc = stopc diff --git a/vendor/github.com/prometheus/alertmanager/notify/email/email.go b/vendor/github.com/prometheus/alertmanager/notify/email/email.go index 73fcf577f0b..33225403b7d 100644 --- a/vendor/github.com/prometheus/alertmanager/notify/email/email.go +++ b/vendor/github.com/prometheus/alertmanager/notify/email/email.go @@ -18,6 +18,7 @@ import ( "context" "crypto/tls" "fmt" + "math/rand" "mime" "mime/multipart" "mime/quotedprintable" @@ -25,6 +26,7 @@ import ( "net/mail" "net/smtp" "net/textproto" + "os" "strings" "time" @@ -41,9 +43,10 @@ import ( // Email implements a Notifier for email notifications. type Email struct { - conf *config.EmailConfig - tmpl *template.Template - logger log.Logger + conf *config.EmailConfig + tmpl *template.Template + logger log.Logger + hostname string } // New returns a new Email notifier. @@ -57,7 +60,13 @@ func New(c *config.EmailConfig, t *template.Template, l log.Logger) *Email { if _, ok := c.Headers["From"]; !ok { c.Headers["From"] = c.From } - return &Email{conf: c, tmpl: t, logger: l} + + h, err := os.Hostname() + // If we can't get the hostname, we'll use localhost + if err != nil { + h = "localhost.localdomain" + } + return &Email{conf: c, tmpl: t, logger: l, hostname: h} } // auth resolves a string of authentication mechanisms. @@ -236,6 +245,10 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { fmt.Fprintf(buffer, "%s: %s\r\n", header, mime.QEncoding.Encode("utf-8", value)) } + if _, ok := n.conf.Headers["Message-Id"]; !ok { + fmt.Fprintf(buffer, "Message-Id: %s\r\n", fmt.Sprintf("<%d.%d@%s>", time.Now().UnixNano(), rand.Uint64(), n.hostname)) + } + multipartBuffer := &bytes.Buffer{} multipartWriter := multipart.NewWriter(multipartBuffer) diff --git a/vendor/github.com/prometheus/alertmanager/notify/notify.go b/vendor/github.com/prometheus/alertmanager/notify/notify.go index 3826383457d..ef112d08e24 100644 --- a/vendor/github.com/prometheus/alertmanager/notify/notify.go +++ b/vendor/github.com/prometheus/alertmanager/notify/notify.go @@ -576,18 +576,19 @@ func (n *DedupStage) Exec(ctx context.Context, l log.Logger, alerts ...*types.Al ctx = WithResolvedAlerts(ctx, resolved) entries, err := n.nflog.Query(nflog.QGroupKey(gkey), nflog.QReceiver(n.recv)) - if err != nil && err != nflog.ErrNotFound { return ctx, nil, err } + var entry *nflogpb.Entry switch len(entries) { case 0: case 1: entry = entries[0] - case 2: + default: return ctx, nil, fmt.Errorf("unexpected entry result size %d", len(entries)) } + if n.needsUpdate(entry, firingSet, resolvedSet, repeatInterval) { return ctx, alerts, nil } diff --git a/vendor/github.com/prometheus/alertmanager/notify/pagerduty/pagerduty.go b/vendor/github.com/prometheus/alertmanager/notify/pagerduty/pagerduty.go index da0ee7a4701..c581f7b1403 100644 --- a/vendor/github.com/prometheus/alertmanager/notify/pagerduty/pagerduty.go +++ b/vendor/github.com/prometheus/alertmanager/notify/pagerduty/pagerduty.go @@ -24,6 +24,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/common/model" @@ -136,17 +137,22 @@ func (n *Notifier) notifyV1( } if tmplErr != nil { - return false, fmt.Errorf("failed to template PagerDuty v1 message: %v", tmplErr) + return false, errors.Wrap(tmplErr, "failed to template PagerDuty v1 message") + } + + // Ensure that the service key isn't empty after templating. + if msg.ServiceKey == "" { + return false, errors.New("service key cannot be empty") } var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(msg); err != nil { - return false, err + return false, errors.Wrap(err, "failed to encode PagerDuty v1 message") } resp, err := notify.PostJSON(ctx, n.client, n.apiV1, &buf) if err != nil { - return true, err + return true, errors.Wrap(err, "failed to post message to PagerDuty v1") } defer notify.Drain(resp) @@ -199,22 +205,27 @@ func (n *Notifier) notifyV2( } for index, item := range n.conf.Links { - msg.Links[index].HRef = tmpl(item.HRef) + msg.Links[index].HRef = tmpl(item.Href) msg.Links[index].Text = tmpl(item.Text) } if tmplErr != nil { - return false, fmt.Errorf("failed to template PagerDuty v2 message: %v", tmplErr) + return false, errors.Wrap(tmplErr, "failed to template PagerDuty v2 message") + } + + // Ensure that the routing key isn't empty after templating. + if msg.RoutingKey == "" { + return false, errors.New("routing key cannot be empty") } var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(msg); err != nil { - return false, fmt.Errorf("failed to encode PagerDuty v2 message: %v", err) + return false, errors.Wrap(err, "failed to encode PagerDuty v2 message") } resp, err := notify.PostJSON(ctx, n.client, n.conf.URL.String(), &buf) if err != nil { - return true, fmt.Errorf("failed to post message to PagerDuty: %v", err) + return true, errors.Wrap(err, "failed to post message to PagerDuty") } defer notify.Drain(resp) @@ -222,8 +233,6 @@ func (n *Notifier) notifyV2( } // Notify implements the Notifier interface. -// -// https://v2.developer.pagerduty.com/docs/events-api-v2 func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { key, err := notify.ExtractGroupKey(ctx) if err != nil { @@ -245,7 +254,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) for k, v := range n.conf.Details { detail, err := n.tmpl.ExecuteTextString(v, data) if err != nil { - return false, fmt.Errorf("failed to template %q: %v", v, err) + return false, errors.Wrapf(err, "%q: failed to template %q", k, v) } details[k] = detail } diff --git a/vendor/github.com/prometheus/alertmanager/notify/wechat/wechat.go b/vendor/github.com/prometheus/alertmanager/notify/wechat/wechat.go index c3e5c726bc1..17c1560356b 100644 --- a/vendor/github.com/prometheus/alertmanager/notify/wechat/wechat.go +++ b/vendor/github.com/prometheus/alertmanager/notify/wechat/wechat.go @@ -171,16 +171,16 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) } defer notify.Drain(resp) + if resp.StatusCode != 200 { + return true, fmt.Errorf("unexpected status code %v", resp.StatusCode) + } + body, err := ioutil.ReadAll(resp.Body) if err != nil { return true, err } level.Debug(n.logger).Log("response", string(body), "incident", key) - if resp.StatusCode != 200 { - return true, fmt.Errorf("unexpected status code %v", resp.StatusCode) - } - var weResp weChatResponse if err := json.Unmarshal(body, &weResp); err != nil { return true, err diff --git a/vendor/github.com/prometheus/alertmanager/pkg/labels/matcher.go b/vendor/github.com/prometheus/alertmanager/pkg/labels/matcher.go new file mode 100644 index 00000000000..7fa5d947e7e --- /dev/null +++ b/vendor/github.com/prometheus/alertmanager/pkg/labels/matcher.go @@ -0,0 +1,88 @@ +// Copyright 2017 The Prometheus 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 labels + +import ( + "fmt" + "regexp" +) + +// MatchType is an enum for label matching types. +type MatchType int + +// Possible MatchTypes. +const ( + MatchEqual MatchType = iota + MatchNotEqual + MatchRegexp + MatchNotRegexp +) + +func (m MatchType) String() string { + typeToStr := map[MatchType]string{ + MatchEqual: "=", + MatchNotEqual: "!=", + MatchRegexp: "=~", + MatchNotRegexp: "!~", + } + if str, ok := typeToStr[m]; ok { + return str + } + panic("unknown match type") +} + +// Matcher models the matching of a label. +type Matcher struct { + Type MatchType + Name string + Value string + + re *regexp.Regexp +} + +// NewMatcher returns a matcher object. +func NewMatcher(t MatchType, n, v string) (*Matcher, error) { + m := &Matcher{ + Type: t, + Name: n, + Value: v, + } + if t == MatchRegexp || t == MatchNotRegexp { + re, err := regexp.Compile("^(?:" + v + ")$") + if err != nil { + return nil, err + } + m.re = re + } + return m, nil +} + +func (m *Matcher) String() string { + return fmt.Sprintf("%s%s%q", m.Name, m.Type, m.Value) +} + +// Matches returns whether the matcher matches the given string value. +func (m *Matcher) Matches(s string) bool { + switch m.Type { + case MatchEqual: + return s == m.Value + case MatchNotEqual: + return s != m.Value + case MatchRegexp: + return m.re.MatchString(s) + case MatchNotRegexp: + return !m.re.MatchString(s) + } + panic("labels.Matcher.Matches: invalid match type") +} diff --git a/vendor/github.com/prometheus/alertmanager/pkg/parse/parse.go b/vendor/github.com/prometheus/alertmanager/pkg/labels/parse.go similarity index 60% rename from vendor/github.com/prometheus/alertmanager/pkg/parse/parse.go rename to vendor/github.com/prometheus/alertmanager/pkg/labels/parse.go index fd526aba1c5..a3fbfb10268 100644 --- a/vendor/github.com/prometheus/alertmanager/pkg/parse/parse.go +++ b/vendor/github.com/prometheus/alertmanager/pkg/labels/parse.go @@ -11,28 +11,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package parse +package labels import ( "fmt" "regexp" "strings" - - "github.com/prometheus/prometheus/pkg/labels" ) var ( re = regexp.MustCompile(`(?:\s?)(\w+)(=|=~|!=|!~)(?:\"([^"=~!]+)\"|([^"=~!]+)|\"\")`) - typeMap = map[string]labels.MatchType{ - "=": labels.MatchEqual, - "!=": labels.MatchNotEqual, - "=~": labels.MatchRegexp, - "!~": labels.MatchNotRegexp, + typeMap = map[string]MatchType{ + "=": MatchEqual, + "!=": MatchNotEqual, + "=~": MatchRegexp, + "!~": MatchNotRegexp, } ) -func Matchers(s string) ([]*labels.Matcher, error) { - matchers := []*labels.Matcher{} +func ParseMatchers(s string) ([]*Matcher, error) { + matchers := []*Matcher{} s = strings.TrimPrefix(s, "{") s = strings.TrimSuffix(s, "}") @@ -54,7 +52,7 @@ func Matchers(s string) ([]*labels.Matcher, error) { tokens = append(tokens, token) } for _, token := range tokens { - m, err := Matcher(token) + m, err := ParseMatcher(token) if err != nil { return nil, err } @@ -64,28 +62,26 @@ func Matchers(s string) ([]*labels.Matcher, error) { return matchers, nil } -func Matcher(s string) (*labels.Matcher, error) { - name, value, matchType, err := Input(s) - if err != nil { - return nil, err - } - - m, err := labels.NewMatcher(matchType, name, value) - if err != nil { - return nil, err - } - return m, nil -} +func ParseMatcher(s string) (*Matcher, error) { + var ( + name, value string + matchType MatchType + ) -func Input(s string) (name, value string, matchType labels.MatchType, err error) { ms := re.FindStringSubmatch(s) if len(ms) < 4 { - return "", "", labels.MatchEqual, fmt.Errorf("bad matcher format: %s", s) + return nil, fmt.Errorf("bad matcher format: %s", s) } - var prs bool name = ms[1] - matchType, prs = typeMap[ms[2]] + if name == "" { + return nil, fmt.Errorf("failed to parse label name") + } + + matchType, found := typeMap[ms[2]] + if !found { + return nil, fmt.Errorf("failed to find match operator") + } if ms[3] != "" { value = ms[3] @@ -93,9 +89,5 @@ func Input(s string) (name, value string, matchType labels.MatchType, err error) value = ms[4] } - if name == "" || !prs { - return "", "", labels.MatchEqual, fmt.Errorf("failed to parse") - } - - return name, value, matchType, nil + return NewMatcher(matchType, name, value) } diff --git a/vendor/github.com/prometheus/alertmanager/provider/mem/mem.go b/vendor/github.com/prometheus/alertmanager/provider/mem/mem.go index 9cae54873f6..575ad0d20b4 100644 --- a/vendor/github.com/prometheus/alertmanager/provider/mem/mem.go +++ b/vendor/github.com/prometheus/alertmanager/provider/mem/mem.go @@ -50,7 +50,7 @@ type listeningAlerts struct { func NewAlerts(ctx context.Context, m types.Marker, intervalGC time.Duration, l log.Logger) (*Alerts, error) { ctx, cancel := context.WithCancel(ctx) a := &Alerts{ - alerts: store.NewAlerts(intervalGC), + alerts: store.NewAlerts(), cancel: cancel, listeners: map[int]listeningAlerts{}, next: 0, @@ -76,7 +76,7 @@ func NewAlerts(ctx context.Context, m types.Marker, intervalGC time.Duration, l } a.mtx.Unlock() }) - a.alerts.Run(ctx) + go a.alerts.Run(ctx, intervalGC) return a, nil } diff --git a/vendor/github.com/prometheus/alertmanager/silence/silence.go b/vendor/github.com/prometheus/alertmanager/silence/silence.go index 6b3e50e6d81..98e533cec47 100644 --- a/vendor/github.com/prometheus/alertmanager/silence/silence.go +++ b/vendor/github.com/prometheus/alertmanager/silence/silence.go @@ -434,6 +434,18 @@ func validateMatcher(m *pb.Matcher) error { return nil } +func matchesEmpty(m *pb.Matcher) bool { + switch m.Type { + case pb.Matcher_EQUAL: + return m.Pattern == "" + case pb.Matcher_REGEXP: + matched, _ := regexp.MatchString(m.Pattern, "") + return matched + default: + return false + } +} + func validateSilence(s *pb.Silence) error { if s.Id == "" { return errors.New("ID missing") @@ -441,10 +453,15 @@ func validateSilence(s *pb.Silence) error { if len(s.Matchers) == 0 { return errors.New("at least one matcher required") } + allMatchEmpty := true for i, m := range s.Matchers { if err := validateMatcher(m); err != nil { return fmt.Errorf("invalid label matcher %d: %s", i, err) } + allMatchEmpty = allMatchEmpty && matchesEmpty(m) + } + if allMatchEmpty { + return errors.New("at least one matcher must not match the empty string") } if s.StartsAt.IsZero() { return errors.New("invalid zero start timestamp") diff --git a/vendor/github.com/prometheus/alertmanager/store/store.go b/vendor/github.com/prometheus/alertmanager/store/store.go index 16f045715bf..488cb451615 100644 --- a/vendor/github.com/prometheus/alertmanager/store/store.go +++ b/vendor/github.com/prometheus/alertmanager/store/store.go @@ -33,23 +33,16 @@ var ( // gcInterval. An optional callback can be set which receives a slice of all // resolved alerts that have been removed. type Alerts struct { - gcInterval time.Duration - sync.Mutex c map[model.Fingerprint]*types.Alert cb func([]*types.Alert) } // NewAlerts returns a new Alerts struct. -func NewAlerts(gcInterval time.Duration) *Alerts { - if gcInterval == 0 { - gcInterval = time.Minute - } - +func NewAlerts() *Alerts { a := &Alerts{ - c: make(map[model.Fingerprint]*types.Alert), - cb: func(_ []*types.Alert) {}, - gcInterval: gcInterval, + c: make(map[model.Fingerprint]*types.Alert), + cb: func(_ []*types.Alert) {}, } return a @@ -63,18 +56,18 @@ func (a *Alerts) SetGCCallback(cb func([]*types.Alert)) { a.cb = cb } -// Run starts the GC loop. -func (a *Alerts) Run(ctx context.Context) { - go func(t *time.Ticker) { - for { - select { - case <-ctx.Done(): - return - case <-t.C: - a.gc() - } +// Run starts the GC loop. The interval must be greater than zero; if not, the function will panic. +func (a *Alerts) Run(ctx context.Context, interval time.Duration) { + t := time.NewTicker(interval) + defer t.Stop() + for { + select { + case <-ctx.Done(): + return + case <-t.C: + a.gc() } - }(time.NewTicker(a.gcInterval)) + } } func (a *Alerts) gc() { diff --git a/vendor/github.com/prometheus/alertmanager/template/template.go b/vendor/github.com/prometheus/alertmanager/template/template.go index 5228a79d948..fed6a3bd410 100644 --- a/vendor/github.com/prometheus/alertmanager/template/template.go +++ b/vendor/github.com/prometheus/alertmanager/template/template.go @@ -141,6 +141,9 @@ var DefaultFuncs = FuncMap{ re := regexp.MustCompile(pattern) return re.ReplaceAllString(text, repl) }, + "stringSlice": func(s ...string) []string { + return s + }, } // Pair is a key/value string pair. diff --git a/vendor/github.com/prometheus/alertmanager/types/match.go b/vendor/github.com/prometheus/alertmanager/types/match.go index b4b4f5b3297..333dca77ab6 100644 --- a/vendor/github.com/prometheus/alertmanager/types/match.go +++ b/vendor/github.com/prometheus/alertmanager/types/match.go @@ -14,12 +14,11 @@ package types import ( + "bytes" "fmt" "regexp" "sort" - "bytes" - "github.com/prometheus/common/model" ) @@ -38,10 +37,11 @@ func (m *Matcher) Init() error { return nil } re, err := regexp.Compile("^(?:" + m.Value + ")$") - if err == nil { - m.regex = re + if err != nil { + return err } - return err + m.regex = re + return nil } func (m *Matcher) String() string { @@ -133,19 +133,6 @@ func (ms Matchers) Less(i, j int) bool { return !ms[i].IsRegex && ms[j].IsRegex } -// Equal returns whether both Matchers are equal. -func (ms Matchers) Equal(o Matchers) bool { - if len(ms) != len(o) { - return false - } - for i, a := range ms { - if *a != *o[i] { - return false - } - } - return true -} - // Match checks whether all matchers are fulfilled against the given label set. func (ms Matchers) Match(lset model.LabelSet) bool { for _, m := range ms { diff --git a/vendor/github.com/prometheus/alertmanager/types/types.go b/vendor/github.com/prometheus/alertmanager/types/types.go index 969a849e986..26f787da459 100644 --- a/vendor/github.com/prometheus/alertmanager/types/types.go +++ b/vendor/github.com/prometheus/alertmanager/types/types.go @@ -204,10 +204,7 @@ func (m *memMarker) SetActive(alert model.Fingerprint) { s, found := m.m[alert] if !found { - s = &AlertStatus{ - SilencedBy: []string{}, - InhibitedBy: []string{}, - } + s = &AlertStatus{} m.m[alert] = s } diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/block.go b/vendor/github.com/thanos-io/thanos/pkg/block/block.go index 6fb43505ccf..740b3d63060 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/block.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/block.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + // Package block contains common functionality for interacting with TSDB blocks // in the context of Thanos. package block @@ -27,8 +30,10 @@ const ( MetaFilename = "meta.json" // IndexFilename is the known index file for block index. IndexFilename = "index" - // IndexCacheFilename is the canonical name for index cache file that stores essential information needed. + // IndexCacheFilename is the canonical name for json index cache file that stores essential information. IndexCacheFilename = "index.cache.json" + // IndexHeaderFilename is the canonical name for binary index header file that stores essential information. + IndexHeaderFilename = "index-header" // ChunksDirname is the known dir name for chunks with compressed samples. ChunksDirname = "chunks" diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/fetcher.go b/vendor/github.com/thanos-io/thanos/pkg/block/fetcher.go index 3fc658e3ba5..b68141531f3 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/fetcher.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/fetcher.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package block import ( @@ -8,6 +11,7 @@ import ( "os" "path" "path/filepath" + "sort" "sync" "time" @@ -18,6 +22,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/relabel" + "github.com/prometheus/prometheus/tsdb" tsdberrors "github.com/prometheus/prometheus/tsdb/errors" "github.com/prometheus/prometheus/tsdb/fileutil" "github.com/thanos-io/thanos/pkg/block/metadata" @@ -46,7 +51,8 @@ const ( // Filter's label values. labelExcludedMeta = "label-excluded" timeExcludedMeta = "time-excluded" - TooFreshMeta = "too-fresh" + tooFreshMeta = "too-fresh" + duplicateMeta = "duplicate" ) func newSyncMetrics(r prometheus.Registerer) *syncMetrics { @@ -77,10 +83,11 @@ func newSyncMetrics(r prometheus.Registerer) *syncMetrics { []string{corruptedMeta}, []string{noMeta}, []string{loadedMeta}, - []string{TooFreshMeta}, + []string{tooFreshMeta}, []string{failedMeta}, []string{labelExcludedMeta}, []string{timeExcludedMeta}, + []string{duplicateMeta}, ) if r != nil { r.MustRegister( @@ -407,3 +414,158 @@ func (f *LabelShardedMetaFilter) Filter(metas map[ulid.ULID]*metadata.Meta, sync delete(metas, id) } } + +// DeduplicateFilter is a MetaFetcher filter that filters out older blocks that have exactly the same data. +type DeduplicateFilter struct { + duplicateIDs []ulid.ULID +} + +// NewDeduplicateFilter creates DeduplicateFilter. +func NewDeduplicateFilter() *DeduplicateFilter { + return &DeduplicateFilter{} +} + +// Filter filters out duplicate blocks that can be formed +// from two or more overlapping blocks that fully submatches the source blocks of the older blocks. +func (f *DeduplicateFilter) Filter(metas map[ulid.ULID]*metadata.Meta, synced GaugeLabeled, _ bool) { + var wg sync.WaitGroup + + metasByResolution := make(map[int64][]*metadata.Meta) + for _, meta := range metas { + res := meta.Thanos.Downsample.Resolution + metasByResolution[res] = append(metasByResolution[res], meta) + } + + for res := range metasByResolution { + wg.Add(1) + go func(res int64) { + defer wg.Done() + f.filterForResolution(NewNode(&metadata.Meta{ + BlockMeta: tsdb.BlockMeta{ + ULID: ulid.MustNew(uint64(0), nil), + }, + }), metasByResolution[res], metas, res, synced) + }(res) + } + + wg.Wait() +} + +func (f *DeduplicateFilter) filterForResolution(root *Node, metaSlice []*metadata.Meta, metas map[ulid.ULID]*metadata.Meta, res int64, synced GaugeLabeled) { + sort.Slice(metaSlice, func(i, j int) bool { + ilen := len(metaSlice[i].Compaction.Sources) + jlen := len(metaSlice[j].Compaction.Sources) + + if ilen == jlen { + return metaSlice[i].ULID.Compare(metaSlice[j].ULID) < 0 + } + + return ilen-jlen > 0 + }) + + for _, meta := range metaSlice { + addNodeBySources(root, NewNode(meta)) + } + + duplicateULIDs := getNonRootIDs(root) + for _, id := range duplicateULIDs { + if metas[id] != nil { + f.duplicateIDs = append(f.duplicateIDs, id) + } + synced.WithLabelValues(duplicateMeta).Inc() + delete(metas, id) + } +} + +// DuplicateIDs returns slice of block ids +// that are filtered out by DeduplicateFilter. +func (f *DeduplicateFilter) DuplicateIDs() []ulid.ULID { + return f.duplicateIDs +} + +func addNodeBySources(root *Node, add *Node) bool { + var rootNode *Node + for _, node := range root.Children { + parentSources := node.Compaction.Sources + childSources := add.Compaction.Sources + + // Block exists with same sources, add as child. + if contains(parentSources, childSources) && contains(childSources, parentSources) { + node.Children = append(node.Children, add) + return true + } + + // Block's sources are present in other block's sources, add as child. + if contains(parentSources, childSources) { + rootNode = node + break + } + } + + // Block cannot be attached to any child nodes, add it as child of root. + if rootNode == nil { + root.Children = append(root.Children, add) + return true + } + + return addNodeBySources(rootNode, add) +} + +func contains(s1 []ulid.ULID, s2 []ulid.ULID) bool { + for _, a := range s2 { + found := false + for _, e := range s1 { + if a.Compare(e) == 0 { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +// ConsistencyDelayMetaFilter is a MetaFetcher filter that filters out blocks that are created before a specified consistency delay. +type ConsistencyDelayMetaFilter struct { + logger log.Logger + consistencyDelay time.Duration +} + +// NewConsistencyDelayMetaFilter creates ConsistencyDelayMetaFilter. +func NewConsistencyDelayMetaFilter(logger log.Logger, consistencyDelay time.Duration, reg prometheus.Registerer) *ConsistencyDelayMetaFilter { + if logger == nil { + logger = log.NewNopLogger() + } + consistencyDelayMetric := prometheus.NewGaugeFunc(prometheus.GaugeOpts{ + Name: "consistency_delay_seconds", + Help: "Configured consistency delay in seconds.", + }, func() float64 { + return consistencyDelay.Seconds() + }) + reg.MustRegister(consistencyDelayMetric) + + return &ConsistencyDelayMetaFilter{ + logger: logger, + consistencyDelay: consistencyDelay, + } +} + +// Filter filters out blocks that filters blocks that have are created before a specified consistency delay. +func (f *ConsistencyDelayMetaFilter) Filter(metas map[ulid.ULID]*metadata.Meta, synced GaugeLabeled, _ bool) { + for id, meta := range metas { + // TODO(khyatisoneji): Remove the checks about Thanos Source + // by implementing delete delay to fetch metas. + // TODO(bwplotka): Check consistency delay based on file upload / modification time instead of ULID. + if ulid.Now()-id.Time() < uint64(f.consistencyDelay/time.Millisecond) && + meta.Thanos.Source != metadata.BucketRepairSource && + meta.Thanos.Source != metadata.CompactorSource && + meta.Thanos.Source != metadata.CompactorRepairSource { + + level.Debug(f.logger).Log("msg", "block is too fresh for now", "block", id) + synced.WithLabelValues(tooFreshMeta).Inc() + delete(metas, id) + } + } +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/index.go b/vendor/github.com/thanos-io/thanos/pkg/block/index.go index 0df14ded4dd..2551aacd9c2 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/index.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/index.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package block import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/binary_reader.go b/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/binary_reader.go new file mode 100644 index 00000000000..9005cd443b8 --- /dev/null +++ b/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/binary_reader.go @@ -0,0 +1,828 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package indexheader + +import ( + "bufio" + "context" + "encoding/binary" + "hash" + "hash/crc32" + "io" + "io/ioutil" + "math" + "os" + "path/filepath" + "sort" + "time" + "unsafe" + + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" + "github.com/oklog/ulid" + "github.com/pkg/errors" + "github.com/prometheus/prometheus/tsdb/encoding" + "github.com/prometheus/prometheus/tsdb/fileutil" + "github.com/prometheus/prometheus/tsdb/index" + "github.com/thanos-io/thanos/pkg/block" + "github.com/thanos-io/thanos/pkg/objstore" + "github.com/thanos-io/thanos/pkg/runutil" +) + +const ( + // BinaryFormatV1 represents first version of index-header file. + BinaryFormatV1 = 1 + + indexTOCLen = 6*8 + crc32.Size + binaryTOCLen = 2*8 + crc32.Size + // headerLen represents number of bytes reserved of index header for header. + headerLen = 4 + 1 + 1 + 8 + + // MagicIndex are 4 bytes at the head of an index-header file. + MagicIndex = 0xBAAAD792 + + symbolFactor = 32 + + postingLengthFieldSize = 4 +) + +// The table gets initialized with sync.Once but may still cause a race +// with any other use of the crc32 package anywhere. Thus we initialize it +// before. +var castagnoliTable *crc32.Table + +func init() { + castagnoliTable = crc32.MakeTable(crc32.Castagnoli) +} + +// newCRC32 initializes a CRC32 hash with a preconfigured polynomial, so the +// polynomial may be easily changed in one location at a later time, if necessary. +func newCRC32() hash.Hash32 { + return crc32.New(castagnoliTable) +} + +// BinaryTOC is a table of content for index-header file. +type BinaryTOC struct { + // Symbols holds start to the same symbols section as index related to this index header. + Symbols uint64 + // PostingsOffsetTable holds start to the the same Postings Offset Table section as index related to this index header. + PostingsOffsetTable uint64 +} + +// WriteBinary build index-header file from the pieces of index in object storage. +func WriteBinary(ctx context.Context, bkt objstore.BucketReader, id ulid.ULID, fn string) (err error) { + ir, indexVersion, err := newChunkedIndexReader(ctx, bkt, id) + if err != nil { + return errors.Wrap(err, "new index reader") + } + + // Buffer for copying and encbuffers. + // This also will control the size of file writer buffer. + buf := make([]byte, 32*1024) + bw, err := newBinaryWriter(fn, buf) + if err != nil { + return errors.Wrap(err, "new binary index header writer") + } + defer runutil.CloseWithErrCapture(&err, bw, "close binary writer for %s", fn) + + if err := bw.AddIndexMeta(indexVersion, ir.toc.PostingsTable); err != nil { + return errors.Wrap(err, "add index meta") + } + + if err := ir.CopySymbols(bw.SymbolsWriter(), buf); err != nil { + return err + } + + if err := bw.f.Flush(); err != nil { + return errors.Wrap(err, "flush") + } + + if err := ir.CopyPostingsOffsets(bw.PostingOffsetsWriter(), buf); err != nil { + return err + } + + if err := bw.f.Flush(); err != nil { + return errors.Wrap(err, "flush") + } + + if err := bw.WriteTOC(); err != nil { + return errors.Wrap(err, "write index header TOC") + } + return nil +} + +type chunkedIndexReader struct { + ctx context.Context + path string + size uint64 + bkt objstore.BucketReader + toc *index.TOC +} + +func newChunkedIndexReader(ctx context.Context, bkt objstore.BucketReader, id ulid.ULID) (*chunkedIndexReader, int, error) { + indexFilepath := filepath.Join(id.String(), block.IndexFilename) + size, err := bkt.ObjectSize(ctx, indexFilepath) + if err != nil { + return nil, 0, errors.Wrapf(err, "get object size of %s", indexFilepath) + } + + rc, err := bkt.GetRange(ctx, indexFilepath, 0, index.HeaderLen) + if err != nil { + return nil, 0, errors.Wrapf(err, "get TOC from object storage of %s", indexFilepath) + } + + b, err := ioutil.ReadAll(rc) + if err != nil { + runutil.CloseWithErrCapture(&err, rc, "close reader") + return nil, 0, errors.Wrapf(err, "get header from object storage of %s", indexFilepath) + } + + if err := rc.Close(); err != nil { + return nil, 0, errors.Wrap(err, "close reader") + } + + if m := binary.BigEndian.Uint32(b[0:4]); m != index.MagicIndex { + return nil, 0, errors.Errorf("invalid magic number %x for %s", m, indexFilepath) + } + + version := int(b[4:5][0]) + + if version != index.FormatV1 && version != index.FormatV2 { + return nil, 0, errors.Errorf("not supported index file version %d of %s", version, indexFilepath) + } + + ir := &chunkedIndexReader{ + ctx: ctx, + path: indexFilepath, + size: size, + bkt: bkt, + } + + toc, err := ir.readTOC() + if err != nil { + return nil, 0, err + } + ir.toc = toc + + return ir, version, nil +} + +func (r *chunkedIndexReader) readTOC() (*index.TOC, error) { + rc, err := r.bkt.GetRange(r.ctx, r.path, int64(r.size-indexTOCLen-crc32.Size), indexTOCLen+crc32.Size) + if err != nil { + return nil, errors.Wrapf(err, "get TOC from object storage of %s", r.path) + } + + tocBytes, err := ioutil.ReadAll(rc) + if err != nil { + runutil.CloseWithErrCapture(&err, rc, "close toc reader") + return nil, errors.Wrapf(err, "get TOC from object storage of %s", r.path) + } + + if err := rc.Close(); err != nil { + return nil, errors.Wrap(err, "close toc reader") + } + + toc, err := index.NewTOCFromByteSlice(realByteSlice(tocBytes)) + if err != nil { + return nil, errors.Wrap(err, "new TOC") + } + return toc, nil +} + +func (r *chunkedIndexReader) CopySymbols(w io.Writer, buf []byte) (err error) { + rc, err := r.bkt.GetRange(r.ctx, r.path, int64(r.toc.Symbols), int64(r.toc.Series-r.toc.Symbols)) + if err != nil { + return errors.Wrapf(err, "get symbols from object storage of %s", r.path) + } + defer runutil.CloseWithErrCapture(&err, rc, "close symbol reader") + + if _, err := io.CopyBuffer(w, rc, buf); err != nil { + return errors.Wrap(err, "copy symbols") + } + + return nil +} + +func (r *chunkedIndexReader) CopyPostingsOffsets(w io.Writer, buf []byte) (err error) { + rc, err := r.bkt.GetRange(r.ctx, r.path, int64(r.toc.PostingsTable), int64(r.size-r.toc.PostingsTable)) + if err != nil { + return errors.Wrapf(err, "get posting offset table from object storage of %s", r.path) + } + defer runutil.CloseWithErrCapture(&err, rc, "close posting offsets reader") + + if _, err := io.CopyBuffer(w, rc, buf); err != nil { + return errors.Wrap(err, "copy posting offsets") + } + + return nil +} + +// TODO(bwplotka): Add padding for efficient read. +type binaryWriter struct { + f *FileWriter + + toc BinaryTOC + + // Reusable memory. + buf encoding.Encbuf + + crc32 hash.Hash +} + +func newBinaryWriter(fn string, buf []byte) (w *binaryWriter, err error) { + dir := filepath.Dir(fn) + + df, err := fileutil.OpenDir(dir) + if os.IsNotExist(err) { + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return nil, err + } + df, err = fileutil.OpenDir(dir) + } + if err != nil { + + return nil, err + } + + defer runutil.CloseWithErrCapture(&err, df, "dir close") + + if err := os.RemoveAll(fn); err != nil { + return nil, errors.Wrap(err, "remove any existing index at path") + } + + // We use file writer for buffers not larger than reused one. + f, err := NewFileWriter(fn, len(buf)) + if err != nil { + return nil, err + } + if err := df.Sync(); err != nil { + return nil, errors.Wrap(err, "sync dir") + } + + w = &binaryWriter{ + f: f, + + // Reusable memory. + buf: encoding.Encbuf{B: buf}, + crc32: newCRC32(), + } + + w.buf.Reset() + w.buf.PutBE32(MagicIndex) + w.buf.PutByte(BinaryFormatV1) + + return w, w.f.Write(w.buf.Get()) +} + +type FileWriter struct { + f *os.File + fbuf *bufio.Writer + pos uint64 + name string +} + +// TODO(bwplotka): Added size to method, upstream this. +func NewFileWriter(name string, size int) (*FileWriter, error) { + f, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR, 0666) + if err != nil { + return nil, err + } + return &FileWriter{ + f: f, + fbuf: bufio.NewWriterSize(f, size), + pos: 0, + name: name, + }, nil +} + +func (fw *FileWriter) Pos() uint64 { + return fw.pos +} + +func (fw *FileWriter) Write(bufs ...[]byte) error { + for _, b := range bufs { + n, err := fw.fbuf.Write(b) + fw.pos += uint64(n) + if err != nil { + return err + } + // For now the index file must not grow beyond 64GiB. Some of the fixed-sized + // offset references in v1 are only 4 bytes large. + // Once we move to compressed/varint representations in those areas, this limitation + // can be lifted. + if fw.pos > 16*math.MaxUint32 { + return errors.Errorf("%q exceeding max size of 64GiB", fw.name) + } + } + return nil +} + +func (fw *FileWriter) Flush() error { + return fw.fbuf.Flush() +} + +func (fw *FileWriter) WriteAt(buf []byte, pos uint64) error { + if err := fw.Flush(); err != nil { + return err + } + _, err := fw.f.WriteAt(buf, int64(pos)) + return err +} + +// AddPadding adds zero byte padding until the file size is a multiple size. +func (fw *FileWriter) AddPadding(size int) error { + p := fw.pos % uint64(size) + if p == 0 { + return nil + } + p = uint64(size) - p + + if err := fw.Write(make([]byte, p)); err != nil { + return errors.Wrap(err, "add padding") + } + return nil +} + +func (fw *FileWriter) Close() error { + if err := fw.Flush(); err != nil { + return err + } + if err := fw.f.Sync(); err != nil { + return err + } + return fw.f.Close() +} + +func (fw *FileWriter) Remove() error { + return os.Remove(fw.name) +} + +func (w *binaryWriter) AddIndexMeta(indexVersion int, indexPostingOffsetTable uint64) error { + w.buf.Reset() + w.buf.PutByte(byte(indexVersion)) + w.buf.PutBE64(indexPostingOffsetTable) + return w.f.Write(w.buf.Get()) +} + +func (w *binaryWriter) SymbolsWriter() io.Writer { + w.toc.Symbols = w.f.Pos() + return w +} + +func (w *binaryWriter) PostingOffsetsWriter() io.Writer { + w.toc.PostingsOffsetTable = w.f.Pos() + return w +} + +func (w *binaryWriter) WriteTOC() error { + w.buf.Reset() + + w.buf.PutBE64(w.toc.Symbols) + w.buf.PutBE64(w.toc.PostingsOffsetTable) + + w.buf.PutHash(w.crc32) + + return w.f.Write(w.buf.Get()) +} + +func (w *binaryWriter) Write(p []byte) (int, error) { + n := w.f.Pos() + err := w.f.Write(p) + return int(w.f.Pos() - n), err +} + +func (w *binaryWriter) Close() error { + return w.f.Close() +} + +type postingValueOffsets struct { + offsets []postingOffset + lastValOffset int64 +} + +type postingOffset struct { + // label value. + value string + // offset of this entry in posting offset table in index-header file. + tableOff int +} + +type BinaryReader struct { + b index.ByteSlice + toc *BinaryTOC + + // Close that releases the underlying resources of the byte slice. + c io.Closer + + // Map of LabelName to a list of some LabelValues's position in the offset table. + // The first and last values for each name are always present. + postings map[string]*postingValueOffsets + // For the v1 format, labelname -> labelvalue -> offset. + postingsV1 map[string]map[string]index.Range + + symbols *index.Symbols + nameSymbols map[uint32]string // Cache of the label name symbol lookups, + // as there are not many and they are half of all lookups. + + dec *index.Decoder + + version int + indexVersion int + indexLastPostingEnd int64 +} + +// NewBinaryReader loads or builds new index-header if not present on disk. +func NewBinaryReader(ctx context.Context, logger log.Logger, bkt objstore.BucketReader, dir string, id ulid.ULID) (*BinaryReader, error) { + binfn := filepath.Join(dir, id.String(), block.IndexHeaderFilename) + br, err := newFileBinaryReader(binfn) + if err == nil { + return br, nil + } + + level.Debug(logger).Log("msg", "failed to read index-header from disk; recreating", "path", binfn, "err", err) + + start := time.Now() + if err := WriteBinary(ctx, bkt, id, binfn); err != nil { + return nil, errors.Wrap(err, "write index header") + } + + level.Debug(logger).Log("msg", "built index-header file", "path", binfn, "elapsed", time.Since(start)) + + return newFileBinaryReader(binfn) +} + +func newFileBinaryReader(path string) (bw *BinaryReader, err error) { + f, err := fileutil.OpenMmapFile(path) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + runutil.CloseWithErrCapture(&err, f, "index header close") + } + }() + + r := &BinaryReader{ + b: realByteSlice(f.Bytes()), + c: f, + postings: map[string]*postingValueOffsets{}, + } + + // Verify header. + if r.b.Len() < headerLen { + return nil, errors.Wrap(encoding.ErrInvalidSize, "index header's header") + } + if m := binary.BigEndian.Uint32(r.b.Range(0, 4)); m != MagicIndex { + return nil, errors.Errorf("invalid magic number %x", m) + } + r.version = int(r.b.Range(4, 5)[0]) + r.indexVersion = int(r.b.Range(5, 6)[0]) + + r.indexLastPostingEnd = int64(binary.BigEndian.Uint64(r.b.Range(6, headerLen))) + + if r.version != BinaryFormatV1 { + return nil, errors.Errorf("unknown index header file version %d", r.version) + } + + r.toc, err = newBinaryTOCFromByteSlice(r.b) + if err != nil { + return nil, errors.Wrap(err, "read index header TOC") + } + + r.symbols, err = index.NewSymbols(r.b, r.indexVersion, int(r.toc.Symbols)) + if err != nil { + return nil, errors.Wrap(err, "read symbols") + } + + var lastKey []string + if r.indexVersion == index.FormatV1 { + // Earlier V1 formats don't have a sorted postings offset table, so + // load the whole offset table into memory. + r.postingsV1 = map[string]map[string]index.Range{} + + var prevRng index.Range + if err := index.ReadOffsetTable(r.b, r.toc.PostingsOffsetTable, func(key []string, off uint64, _ int) error { + if len(key) != 2 { + return errors.Errorf("unexpected key length for posting table %d", len(key)) + } + + if lastKey != nil { + prevRng.End = int64(off - crc32.Size) + r.postingsV1[lastKey[0]][lastKey[1]] = prevRng + } + + if _, ok := r.postingsV1[key[0]]; !ok { + r.postingsV1[key[0]] = map[string]index.Range{} + r.postings[key[0]] = nil // Used to get a list of labelnames in places. + } + + lastKey = key + prevRng = index.Range{Start: int64(off + postingLengthFieldSize)} + return nil + }); err != nil { + return nil, errors.Wrap(err, "read postings table") + } + if lastKey != nil { + prevRng.End = r.indexLastPostingEnd - crc32.Size + r.postingsV1[lastKey[0]][lastKey[1]] = prevRng + } + } else { + lastTableOff := 0 + valueCount := 0 + + // For the postings offset table we keep every label name but only every nth + // label value (plus the first and last one), to save memory. + if err := index.ReadOffsetTable(r.b, r.toc.PostingsOffsetTable, func(key []string, off uint64, tableOff int) error { + if len(key) != 2 { + return errors.Errorf("unexpected key length for posting table %d", len(key)) + } + + if _, ok := r.postings[key[0]]; !ok { + // Next label name. + r.postings[key[0]] = &postingValueOffsets{} + if lastKey != nil { + if valueCount%symbolFactor != 0 { + // Always include last value for each label name. + r.postings[lastKey[0]].offsets = append(r.postings[lastKey[0]].offsets, postingOffset{value: lastKey[1], tableOff: lastTableOff}) + } + r.postings[lastKey[0]].lastValOffset = int64(off - crc32.Size) + lastKey = nil + } + valueCount = 0 + } + + lastKey = key + if valueCount%symbolFactor == 0 { + r.postings[key[0]].offsets = append(r.postings[key[0]].offsets, postingOffset{value: key[1], tableOff: tableOff}) + return nil + } + + lastTableOff = tableOff + valueCount++ + return nil + }); err != nil { + return nil, errors.Wrap(err, "read postings table") + } + if lastKey != nil { + if valueCount%symbolFactor != 0 { + r.postings[lastKey[0]].offsets = append(r.postings[lastKey[0]].offsets, postingOffset{value: lastKey[1], tableOff: lastTableOff}) + } + r.postings[lastKey[0]].lastValOffset = r.indexLastPostingEnd - crc32.Size + } + // Trim any extra space in the slices. + for k, v := range r.postings { + l := make([]postingOffset, len(v.offsets)) + copy(l, v.offsets) + r.postings[k].offsets = l + } + } + + r.nameSymbols = make(map[uint32]string, len(r.postings)) + for k := range r.postings { + if k == "" { + continue + } + off, err := r.symbols.ReverseLookup(k) + if err != nil { + return nil, errors.Wrap(err, "reverse symbol lookup") + } + r.nameSymbols[off] = k + } + + r.dec = &index.Decoder{LookupSymbol: r.LookupSymbol} + + return r, nil +} + +// newBinaryTOCFromByteSlice return parsed TOC from given index header byte slice. +func newBinaryTOCFromByteSlice(bs index.ByteSlice) (*BinaryTOC, error) { + if bs.Len() < binaryTOCLen { + return nil, encoding.ErrInvalidSize + } + b := bs.Range(bs.Len()-binaryTOCLen, bs.Len()) + + expCRC := binary.BigEndian.Uint32(b[len(b)-4:]) + d := encoding.Decbuf{B: b[:len(b)-4]} + + if d.Crc32(castagnoliTable) != expCRC { + return nil, errors.Wrap(encoding.ErrInvalidChecksum, "read index header TOC") + } + + if err := d.Err(); err != nil { + return nil, err + } + + return &BinaryTOC{ + Symbols: d.Be64(), + PostingsOffsetTable: d.Be64(), + }, nil +} + +func (r BinaryReader) IndexVersion() int { + return r.indexVersion +} + +// TODO(bwplotka): Get advantage of multi value offset fetch. +func (r BinaryReader) PostingsOffset(name string, value string) (index.Range, error) { + rngs, err := r.postingsOffset(name, value) + if err != nil { + return index.Range{}, err + } + if len(rngs) != 1 { + return index.Range{}, NotFoundRangeErr + } + return rngs[0], nil +} + +func (r BinaryReader) postingsOffset(name string, values ...string) ([]index.Range, error) { + rngs := make([]index.Range, 0, len(values)) + if r.indexVersion == index.FormatV1 { + e, ok := r.postingsV1[name] + if !ok { + return nil, nil + } + for _, v := range values { + rng, ok := e[v] + if !ok { + continue + } + rngs = append(rngs, rng) + } + return rngs, nil + } + + e, ok := r.postings[name] + if !ok { + return nil, nil + } + + if len(values) == 0 { + return nil, nil + } + + skip := 0 + valueIndex := 0 + for valueIndex < len(values) && values[valueIndex] < e.offsets[0].value { + // Discard values before the start. + valueIndex++ + } + + var tmpRngs []index.Range // The start, end offsets in the postings table in the original index file. + for valueIndex < len(values) { + value := values[valueIndex] + + i := sort.Search(len(e.offsets), func(i int) bool { return e.offsets[i].value >= value }) + if i == len(e.offsets) { + // We're past the end. + break + } + if i > 0 && e.offsets[i].value != value { + // Need to look from previous entry. + i-- + } + // Don't Crc32 the entire postings offset table, this is very slow + // so hope any issues were caught at startup. + d := encoding.NewDecbufAt(r.b, int(r.toc.PostingsOffsetTable), nil) + d.Skip(e.offsets[i].tableOff) + + tmpRngs = tmpRngs[:0] + // Iterate on the offset table. + for d.Err() == nil { + if skip == 0 { + // These are always the same number of bytes, + // and it's faster to skip than parse. + skip = d.Len() + d.Uvarint() // Keycount. + d.UvarintBytes() // Label name. + skip -= d.Len() + } else { + d.Skip(skip) + } + v := d.UvarintBytes() // Label value. + postingOffset := int64(d.Uvarint64()) // Offset. + for string(v) >= value { + if string(v) == value { + tmpRngs = append(tmpRngs, index.Range{Start: postingOffset + postingLengthFieldSize}) + } + valueIndex++ + if valueIndex == len(values) { + break + } + value = values[valueIndex] + } + if i+1 == len(e.offsets) { + for i := range tmpRngs { + tmpRngs[i].End = e.lastValOffset + } + rngs = append(rngs, tmpRngs...) + // Need to go to a later postings offset entry, if there is one. + break + } + + if value >= e.offsets[i+1].value || valueIndex == len(values) { + d.Skip(skip) + d.UvarintBytes() // Label value. + postingOffset := int64(d.Uvarint64()) // Offset. + for j := range tmpRngs { + tmpRngs[j].End = postingOffset - crc32.Size + } + rngs = append(rngs, tmpRngs...) + // Need to go to a later postings offset entry, if there is one. + break + } + } + if d.Err() != nil { + return nil, errors.Wrap(d.Err(), "get postings offset entry") + } + } + + return rngs, nil +} + +func (r BinaryReader) LookupSymbol(o uint32) (string, error) { + if s, ok := r.nameSymbols[o]; ok { + return s, nil + } + + if r.indexVersion == index.FormatV1 { + // For v1 little trick is needed. Refs are actual offset inside index, not index-header. This is different + // of the header length difference between two files. + o += headerLen - index.HeaderLen + } + + return r.symbols.Lookup(o) +} + +func (r BinaryReader) LabelValues(name string) ([]string, error) { + if r.indexVersion == index.FormatV1 { + e, ok := r.postingsV1[name] + if !ok { + return nil, nil + } + values := make([]string, 0, len(e)) + for k := range e { + values = append(values, k) + } + sort.Strings(values) + return values, nil + + } + e, ok := r.postings[name] + if !ok { + return nil, nil + } + if len(e.offsets) == 0 { + return nil, nil + } + values := make([]string, 0, len(e.offsets)*symbolFactor) + + d := encoding.NewDecbufAt(r.b, int(r.toc.PostingsOffsetTable), nil) + d.Skip(e.offsets[0].tableOff) + lastVal := e.offsets[len(e.offsets)-1].value + + skip := 0 + for d.Err() == nil { + if skip == 0 { + // These are always the same number of bytes, + // and it's faster to skip than parse. + skip = d.Len() + d.Uvarint() // Keycount. + d.UvarintBytes() // Label name. + skip -= d.Len() + } else { + d.Skip(skip) + } + s := yoloString(d.UvarintBytes()) // Label value. + values = append(values, s) + if s == lastVal { + break + } + d.Uvarint64() // Offset. + } + if d.Err() != nil { + return nil, errors.Wrap(d.Err(), "get postings offset entry") + } + return values, nil +} + +func yoloString(b []byte) string { + return *((*string)(unsafe.Pointer(&b))) +} + +func (r BinaryReader) LabelNames() []string { + allPostingsKeyName, _ := index.AllPostingsKey() + labelNames := make([]string, 0, len(r.postings)) + for name := range r.postings { + if name == allPostingsKeyName { + // This is not from any metric. + continue + } + labelNames = append(labelNames, name) + } + sort.Strings(labelNames) + return labelNames +} + +func (r *BinaryReader) Close() error { return r.c.Close() } diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/header.go b/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/header.go index 2f3b2fbbcc4..dbbe335deb8 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/header.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/header.go @@ -1,19 +1,40 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package indexheader import ( + "io" + + "github.com/pkg/errors" "github.com/prometheus/prometheus/tsdb/index" ) -// NotFoundRange is a range returned by PostingsOffset when there is no posting for given name and value pairs. -// Has to be default value of index.Range. -var NotFoundRange = index.Range{} +// NotFoundRangeErr is an error returned by PostingsOffset when there is no posting for given name and value pairs. +var NotFoundRangeErr = errors.New("range not found") -// Reader is an interface allowing to read essential, minimal number of index entries from the small portion of index file called header. +// Reader is an interface allowing to read essential, minimal number of index fields from the small portion of index file called header. type Reader interface { + io.Closer + + // IndexVersion returns version of index. IndexVersion() int + + // PostingsOffset returns start and end offsets of postings for given name and value. + // The end offset might be bigger than the actual posting ending, but not larger than the whole index file. + // NotFoundRangeErr is returned when no index can be found for given name and value. // TODO(bwplotka): Move to PostingsOffsets(name string, value ...string) []index.Range and benchmark. - PostingsOffset(name string, value string) index.Range + PostingsOffset(name string, value string) (index.Range, error) + + // LookupSymbol returns string based on given reference. + // Error is return if the symbol can't be found. LookupSymbol(o uint32) (string, error) - LabelValues(name string) []string + + // LabelValues returns all label values for given label name or error. + // If no values are found for label name, or label name does not exists, + // then empty string is returned and no error. + LabelValues(name string) ([]string, error) + + // LabelNames returns all label names. LabelNames() []string } diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/json_reader.go b/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/json_reader.go index cf0277a9298..5a3654f4d60 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/json_reader.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/indexheader/json_reader.go @@ -1,9 +1,11 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package indexheader import ( "context" "encoding/json" - "hash/crc32" "io/ioutil" "os" "path/filepath" @@ -58,15 +60,6 @@ func (b realByteSlice) Sub(start, end int) index.ByteSlice { return b[start:end] } -// The table gets initialized with sync.Once but may still cause a race -// with any other use of the crc32 package anywhere. Thus we initialize it -// before. -var castagnoliTable *crc32.Table - -func init() { - castagnoliTable = crc32.MakeTable(crc32.Castagnoli) -} - // readSymbols reads the symbol table fully into memory and allocates proper strings for them. // Strings backed by the mmap'd memory would cause memory faults if applications keep using them // after the reader is closed. @@ -126,7 +119,6 @@ func getSymbolTable(b index.ByteSlice) (map[uint32]string, error) { for o, s := range symbolsV2 { symbolsTable[uint32(o)] = s } - return symbolsTable, nil } @@ -206,20 +198,26 @@ type JSONReader struct { postings map[labels.Label]index.Range } +// NewJSONReader loads or builds new index-cache.json if not present on disk or object storage. func NewJSONReader(ctx context.Context, logger log.Logger, bkt objstore.BucketReader, dir string, id ulid.ULID) (*JSONReader, error) { cachefn := filepath.Join(dir, id.String(), block.IndexCacheFilename) - jr, err := newJSONReaderFromFile(logger, cachefn) + jr, err := newFileJSONReader(logger, cachefn) if err == nil { - return jr, err + return jr, nil } if !os.IsNotExist(errors.Cause(err)) && errors.Cause(err) != jsonUnmarshalError { return nil, errors.Wrap(err, "read index cache") } + // Just in case the dir was not created. + if err := os.MkdirAll(filepath.Join(dir, id.String()), os.ModePerm); err != nil { + return nil, errors.Wrap(err, "create dir") + } + // Try to download index cache file from object store. if err = objstore.DownloadFile(ctx, logger, bkt, filepath.Join(id.String(), block.IndexCacheFilename), cachefn); err == nil { - return newJSONReaderFromFile(logger, cachefn) + return newFileJSONReader(logger, cachefn) } if !bkt.IsObjNotFoundErr(errors.Cause(err)) && errors.Cause(err) != jsonUnmarshalError { @@ -243,16 +241,16 @@ func NewJSONReader(ctx context.Context, logger log.Logger, bkt objstore.BucketRe return nil, errors.Wrap(err, "write index cache") } - return newJSONReaderFromFile(logger, cachefn) + return newFileJSONReader(logger, cachefn) } // ReadJSON reads an index cache file. -func newJSONReaderFromFile(logger log.Logger, fn string) (*JSONReader, error) { +func newFileJSONReader(logger log.Logger, fn string) (*JSONReader, error) { f, err := os.Open(fn) if err != nil { return nil, errors.Wrap(err, "open file") } - defer runutil.CloseWithLogOnErr(logger, f, "index reader") + defer runutil.CloseWithLogOnErr(logger, f, "index cache json close") var v indexCache @@ -317,20 +315,29 @@ func (r *JSONReader) IndexVersion() int { func (r *JSONReader) LookupSymbol(o uint32) (string, error) { idx := int(o) if idx >= len(r.symbols) { - return "", errors.Errorf("bucketIndexReader: unknown symbol offset %d", o) + return "", errors.Errorf("indexJSONReader: unknown symbol offset %d", o) } - + // NOTE: This is not entirely correct, symbols slice can have gaps. Not fixing as JSON reader + // is replaced by index-header. return r.symbols[idx], nil } -func (r *JSONReader) PostingsOffset(name, value string) index.Range { - return r.postings[labels.Label{Name: name, Value: value}] +func (r *JSONReader) PostingsOffset(name, value string) (index.Range, error) { + rng, ok := r.postings[labels.Label{Name: name, Value: value}] + if !ok { + return index.Range{}, NotFoundRangeErr + } + return rng, nil } // LabelValues returns label values for single name. -func (r *JSONReader) LabelValues(name string) []string { - res := make([]string, 0, len(r.lvals[name])) - return append(res, r.lvals[name]...) +func (r *JSONReader) LabelValues(name string) ([]string, error) { + vals, ok := r.lvals[name] + if !ok { + return nil, nil + } + res := make([]string, 0, len(vals)) + return append(res, vals...), nil } // LabelNames returns a list of label names. @@ -342,3 +349,5 @@ func (r *JSONReader) LabelNames() []string { sort.Strings(res) return res } + +func (r *JSONReader) Close() error { return nil } diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/metadata/meta.go b/vendor/github.com/thanos-io/thanos/pkg/block/metadata/meta.go index fd664c1aa3a..b57b57722fc 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/metadata/meta.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/metadata/meta.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package metadata // metadata package implements writing and reading wrapped meta.json where Thanos puts its metadata. diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/node.go b/vendor/github.com/thanos-io/thanos/pkg/block/node.go new file mode 100644 index 00000000000..1423e31ed50 --- /dev/null +++ b/vendor/github.com/thanos-io/thanos/pkg/block/node.go @@ -0,0 +1,53 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package block + +import ( + "github.com/oklog/ulid" + "github.com/thanos-io/thanos/pkg/block/metadata" +) + +// Node type represents a node of a tree. +type Node struct { + metadata.Meta + Children []*Node +} + +// NewNode creates a new node with children as empty slice. +func NewNode(meta *metadata.Meta) *Node { + return &Node{ + Meta: *meta, + Children: []*Node{}, + } +} + +// getNonRootIDs returns list of ids which are not on root level. +func getNonRootIDs(root *Node) []ulid.ULID { + var ulids []ulid.ULID + for _, node := range root.Children { + ulids = append(ulids, childrenToULIDs(node)...) + ulids = remove(ulids, node.ULID) + } + return ulids +} + +func childrenToULIDs(a *Node) []ulid.ULID { + var ulids = []ulid.ULID{a.ULID} + for _, childNode := range a.Children { + ulids = append(ulids, childrenToULIDs(childNode)...) + } + return ulids +} + +func remove(items []ulid.ULID, item ulid.ULID) []ulid.ULID { + newitems := []ulid.ULID{} + + for _, i := range items { + if i.Compare(item) != 0 { + newitems = append(newitems, i) + } + } + + return newitems +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/cacheutil/jump_hash.go b/vendor/github.com/thanos-io/thanos/pkg/cacheutil/jump_hash.go index 4b684b73840..cd962773f92 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/cacheutil/jump_hash.go +++ b/vendor/github.com/thanos-io/thanos/pkg/cacheutil/jump_hash.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package cacheutil // jumpHash consistently chooses a hash bucket number in the range diff --git a/vendor/github.com/thanos-io/thanos/pkg/cacheutil/memcached_client.go b/vendor/github.com/thanos-io/thanos/pkg/cacheutil/memcached_client.go index 91d4552dd1a..2785f59d004 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/cacheutil/memcached_client.go +++ b/vendor/github.com/thanos-io/thanos/pkg/cacheutil/memcached_client.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package cacheutil import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/cacheutil/memcached_server_selector.go b/vendor/github.com/thanos-io/thanos/pkg/cacheutil/memcached_server_selector.go index 37b693367cb..00a122e0752 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/cacheutil/memcached_server_selector.go +++ b/vendor/github.com/thanos-io/thanos/pkg/cacheutil/memcached_server_selector.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package cacheutil import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/compact/clean.go b/vendor/github.com/thanos-io/thanos/pkg/compact/clean.go index 7fa085eebc8..af681a940e4 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/compact/clean.go +++ b/vendor/github.com/thanos-io/thanos/pkg/compact/clean.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package compact import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/compact/compact.go b/vendor/github.com/thanos-io/thanos/pkg/compact/compact.go index b9f5332fd6d..3a963783f83 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/compact/compact.go +++ b/vendor/github.com/thanos-io/thanos/pkg/compact/compact.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package compact import ( @@ -46,6 +49,7 @@ type Syncer struct { metrics *syncerMetrics acceptMalformedIndex bool enableVerticalCompaction bool + duplicateBlocksFilter *block.DeduplicateFilter } type syncerMetrics struct { @@ -120,19 +124,20 @@ func newSyncerMetrics(reg prometheus.Registerer) *syncerMetrics { // NewMetaSyncer returns a new Syncer for the given Bucket and directory. // Blocks must be at least as old as the sync delay for being considered. -func NewSyncer(logger log.Logger, reg prometheus.Registerer, bkt objstore.Bucket, fetcher block.MetadataFetcher, blockSyncConcurrency int, acceptMalformedIndex bool, enableVerticalCompaction bool) (*Syncer, error) { +func NewSyncer(logger log.Logger, reg prometheus.Registerer, bkt objstore.Bucket, fetcher block.MetadataFetcher, duplicateBlocksFilter *block.DeduplicateFilter, blockSyncConcurrency int, acceptMalformedIndex bool, enableVerticalCompaction bool) (*Syncer, error) { if logger == nil { logger = log.NewNopLogger() } return &Syncer{ - logger: logger, - reg: reg, - bkt: bkt, - fetcher: fetcher, - blocks: map[ulid.ULID]*metadata.Meta{}, - metrics: newSyncerMetrics(reg), - blockSyncConcurrency: blockSyncConcurrency, - acceptMalformedIndex: acceptMalformedIndex, + logger: logger, + reg: reg, + bkt: bkt, + fetcher: fetcher, + blocks: map[ulid.ULID]*metadata.Meta{}, + metrics: newSyncerMetrics(reg), + duplicateBlocksFilter: duplicateBlocksFilter, + blockSyncConcurrency: blockSyncConcurrency, + acceptMalformedIndex: acceptMalformedIndex, // The syncer offers an option to enable vertical compaction, even if it's // not currently used by Thanos, because the compactor is also used by Cortex // which needs vertical compaction. @@ -187,26 +192,27 @@ func (s *Syncer) Groups() (res []*Group, err error) { groups := map[string]*Group{} for _, m := range s.blocks { - g, ok := groups[GroupKey(m.Thanos)] + groupKey := GroupKey(m.Thanos) + g, ok := groups[groupKey] if !ok { g, err = newGroup( - log.With(s.logger, "compactionGroup", GroupKey(m.Thanos)), + log.With(s.logger, "compactionGroup", groupKey), s.bkt, labels.FromMap(m.Thanos.Labels), m.Thanos.Downsample.Resolution, s.acceptMalformedIndex, s.enableVerticalCompaction, - s.metrics.compactions.WithLabelValues(GroupKey(m.Thanos)), - s.metrics.compactionRunsStarted.WithLabelValues(GroupKey(m.Thanos)), - s.metrics.compactionRunsCompleted.WithLabelValues(GroupKey(m.Thanos)), - s.metrics.compactionFailures.WithLabelValues(GroupKey(m.Thanos)), - s.metrics.verticalCompactions.WithLabelValues(GroupKey(m.Thanos)), + s.metrics.compactions.WithLabelValues(groupKey), + s.metrics.compactionRunsStarted.WithLabelValues(groupKey), + s.metrics.compactionRunsCompleted.WithLabelValues(groupKey), + s.metrics.compactionFailures.WithLabelValues(groupKey), + s.metrics.verticalCompactions.WithLabelValues(groupKey), s.metrics.garbageCollectedBlocks, ) if err != nil { return nil, errors.Wrap(err, "create compaction group") } - groups[GroupKey(m.Thanos)] = g + groups[groupKey] = g res = append(res, g) } if err := g.Add(m); err != nil { @@ -221,95 +227,14 @@ func (s *Syncer) Groups() (res []*Group, err error) { // GarbageCollect deletes blocks from the bucket if their data is available as part of a // block with a higher compaction level. +// Call to SyncMetas function is required to populate duplicateIDs in duplicateBlocksFilter. func (s *Syncer) GarbageCollect(ctx context.Context) error { s.mtx.Lock() defer s.mtx.Unlock() begin := time.Now() - // Run a separate round of garbage collections for each valid resolution. - for _, res := range []int64{ - downsample.ResLevel0, downsample.ResLevel1, downsample.ResLevel2, - } { - err := s.garbageCollect(ctx, res) - if err != nil { - s.metrics.garbageCollectionFailures.Inc() - } - s.metrics.garbageCollections.Inc() - s.metrics.garbageCollectionDuration.Observe(time.Since(begin).Seconds()) - - if err != nil { - return errors.Wrapf(err, "garbage collect resolution %d", res) - } - } - return nil -} - -func (s *Syncer) GarbageBlocks(resolution int64) (ids []ulid.ULID, err error) { - // Map each block to its highest priority parent. Initial blocks have themselves - // in their source section, i.e. are their own parent. - parents := map[ulid.ULID]ulid.ULID{} - - for id, meta := range s.blocks { - // Skip any block that has a different resolution. - if meta.Thanos.Downsample.Resolution != resolution { - continue - } - - // For each source block we contain, check whether we are the highest priority parent block. - for _, sid := range meta.Compaction.Sources { - pid, ok := parents[sid] - // No parents for the source block so far. - if !ok { - parents[sid] = id - continue - } - pmeta, ok := s.blocks[pid] - if !ok { - return nil, errors.Errorf("previous parent block %s not found", pid) - } - // The current block is the higher priority parent for the source if its - // compaction level is higher than that of the previously set parent. - // If compaction levels are equal, the more recent ULID wins. - // - // The ULID recency alone is not sufficient since races, e.g. induced - // by downtime of garbage collection, may re-compact blocks that are - // were already compacted into higher-level blocks multiple times. - level, plevel := meta.Compaction.Level, pmeta.Compaction.Level - - if level > plevel || (level == plevel && id.Compare(pid) > 0) { - parents[sid] = id - } - } - } - - // A block can safely be deleted if they are not the highest priority parent for - // any source block. - topParents := map[ulid.ULID]struct{}{} - for _, pid := range parents { - topParents[pid] = struct{}{} - } - - for id, meta := range s.blocks { - // Skip any block that has a different resolution. - if meta.Thanos.Downsample.Resolution != resolution { - continue - } - if _, ok := topParents[id]; ok { - continue - } - - ids = append(ids, id) - } - return ids, nil -} - -func (s *Syncer) garbageCollect(ctx context.Context, resolution int64) error { - garbageIds, err := s.GarbageBlocks(resolution) - if err != nil { - return err - } - + garbageIds := s.duplicateBlocksFilter.DuplicateIDs() for _, id := range garbageIds { if ctx.Err() != nil { return ctx.Err() @@ -323,6 +248,7 @@ func (s *Syncer) garbageCollect(ctx context.Context, resolution int64) error { err := block.Delete(delCtx, s.logger, s.bkt, id) cancel() if err != nil { + s.metrics.garbageCollectionFailures.Inc() return retry(errors.Wrapf(err, "delete block %s from bucket", id)) } @@ -331,6 +257,8 @@ func (s *Syncer) garbageCollect(ctx context.Context, resolution int64) error { delete(s.blocks, id) s.metrics.garbageCollectedBlocks.Inc() } + s.metrics.garbageCollections.Inc() + s.metrics.garbageCollectionDuration.Observe(time.Since(begin).Seconds()) return nil } @@ -687,8 +615,9 @@ func (cg *Group) compact(ctx context.Context, dir string, comp tsdb.Compactor) ( return false, ulid.ULID{}, errors.Wrapf(err, "read meta from %s", pdir) } - if cg.Key() != GroupKey(meta.Thanos) { - return false, ulid.ULID{}, halt(errors.Wrapf(err, "compact planned compaction for mixed groups. group: %s, planned block's group: %s", cg.Key(), GroupKey(meta.Thanos))) + cgKey, groupKey := cg.Key(), GroupKey(meta.Thanos) + if cgKey != groupKey { + return false, ulid.ULID{}, halt(errors.Wrapf(err, "compact planned compaction for mixed groups. group: %s, planned block's group: %s", cgKey, groupKey)) } for _, s := range meta.Compaction.Sources { diff --git a/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/aggr.go b/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/aggr.go index 9a96e945715..db5f914e12b 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/aggr.go +++ b/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/aggr.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package downsample import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/downsample.go b/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/downsample.go index 5bcfccc81b9..5e14c26bb35 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/downsample.go +++ b/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/downsample.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package downsample import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/pool.go b/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/pool.go index f591b16548a..68dec1227e3 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/pool.go +++ b/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/pool.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package downsample import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/streamed_block_writer.go b/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/streamed_block_writer.go index bde6397869d..267a93bfabf 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/streamed_block_writer.go +++ b/vendor/github.com/thanos-io/thanos/pkg/compact/downsample/streamed_block_writer.go @@ -1,9 +1,13 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package downsample import ( "context" "io" "path/filepath" + "strings" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" @@ -108,7 +112,7 @@ func (w *streamedBlockWriter) WriteSeries(lset labels.Labels, chunks []chunks.Me } if len(chunks) == 0 { - level.Warn(w.logger).Log("empty chunks happened, skip series", lset) + level.Warn(w.logger).Log("msg", "empty chunks happened, skip series", "series", strings.ReplaceAll(lset.String(), "\"", "'")) return nil } diff --git a/vendor/github.com/thanos-io/thanos/pkg/compact/retention.go b/vendor/github.com/thanos-io/thanos/pkg/compact/retention.go index aba46963ecc..47f61f0cfbf 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/compact/retention.go +++ b/vendor/github.com/thanos-io/thanos/pkg/compact/retention.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package compact import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/component/component.go b/vendor/github.com/thanos-io/thanos/pkg/component/component.go index d00966fc2e3..675caa60343 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/component/component.go +++ b/vendor/github.com/thanos-io/thanos/pkg/component/component.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package component import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/lookup.go b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/lookup.go index 831eae64d76..4e3fb492e2e 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/lookup.go +++ b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/lookup.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package miekgdns import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/resolver.go b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/resolver.go index 06b0b25a1af..e62660f12c8 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/resolver.go +++ b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/resolver.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package miekgdns import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/provider.go b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/provider.go index 332135ba17e..a3e07307309 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/provider.go +++ b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/provider.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package dns import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/resolver.go b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/resolver.go index 709e264e57a..ef730547689 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/resolver.go +++ b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/resolver.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package dns import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/exthttp/transport.go b/vendor/github.com/thanos-io/thanos/pkg/exthttp/transport.go index 92725c9b337..60e82e2cc8e 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/exthttp/transport.go +++ b/vendor/github.com/thanos-io/thanos/pkg/exthttp/transport.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package exthttp import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/extprom/extprom.go b/vendor/github.com/thanos-io/thanos/pkg/extprom/extprom.go index f2d7d09ab1d..5da95f3b172 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/extprom/extprom.go +++ b/vendor/github.com/thanos-io/thanos/pkg/extprom/extprom.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package extprom import "github.com/prometheus/client_golang/prometheus" diff --git a/vendor/github.com/thanos-io/thanos/pkg/extprom/testing.go b/vendor/github.com/thanos-io/thanos/pkg/extprom/testing.go new file mode 100644 index 00000000000..5db80b26e2a --- /dev/null +++ b/vendor/github.com/thanos-io/thanos/pkg/extprom/testing.go @@ -0,0 +1,35 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package extprom + +import ( + "testing" + + "github.com/prometheus/client_golang/prometheus" + "github.com/thanos-io/thanos/pkg/testutil" +) + +// CurrentGaugeValuesFor returns gauge values for given metric names. Useful for testing based on registry, +// when you don't have access to metric variable. +func CurrentGaugeValuesFor(t *testing.T, reg prometheus.Gatherer, metricNames ...string) map[string]float64 { + f, err := reg.Gather() + testutil.Ok(t, err) + + res := make(map[string]float64, len(metricNames)) + for _, g := range f { + for _, m := range metricNames { + if g.GetName() != m { + continue + } + + testutil.Equals(t, 1, len(g.GetMetric())) + if _, ok := res[m]; ok { + t.Error("expected only one metric family for", m) + t.FailNow() + } + res[m] = *g.GetMetric()[0].GetGauge().Value + } + } + return res +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/extprom/tx_gauge.go b/vendor/github.com/thanos-io/thanos/pkg/extprom/tx_gauge.go index d0ee7342e6f..d85bf4f9215 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/extprom/tx_gauge.go +++ b/vendor/github.com/thanos-io/thanos/pkg/extprom/tx_gauge.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package extprom import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/gate/gate.go b/vendor/github.com/thanos-io/thanos/pkg/gate/gate.go index 78aeefe671c..43bc3a47b4c 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/gate/gate.go +++ b/vendor/github.com/thanos-io/thanos/pkg/gate/gate.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package gate import ( @@ -8,6 +11,11 @@ import ( "github.com/prometheus/prometheus/pkg/gate" ) +type Gater interface { + IsMyTurn(ctx context.Context) error + Done() +} + // Gate wraps the Prometheus gate with extra metrics. type Gate struct { g *gate.Gate diff --git a/vendor/github.com/thanos-io/thanos/pkg/model/timeduration.go b/vendor/github.com/thanos-io/thanos/pkg/model/timeduration.go index bbe766043ff..1d525136f09 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/model/timeduration.go +++ b/vendor/github.com/thanos-io/thanos/pkg/model/timeduration.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package model import ( @@ -42,7 +45,7 @@ func (tdv *TimeOrDurationValue) Set(s string) error { return nil } -// String returns either tume or duration. +// String returns either time or duration. func (tdv *TimeOrDurationValue) String() string { switch { case tdv.Time != nil: diff --git a/vendor/github.com/thanos-io/thanos/pkg/objstore/azure/azure.go b/vendor/github.com/thanos-io/thanos/pkg/objstore/azure/azure.go index b5ef93ab3de..0c132daf61b 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/objstore/azure/azure.go +++ b/vendor/github.com/thanos-io/thanos/pkg/objstore/azure/azure.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package azure import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/objstore/azure/helpers.go b/vendor/github.com/thanos-io/thanos/pkg/objstore/azure/helpers.go index 86a76f0911b..0189a49acf9 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/objstore/azure/helpers.go +++ b/vendor/github.com/thanos-io/thanos/pkg/objstore/azure/helpers.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package azure import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/objstore/gcs/gcs.go b/vendor/github.com/thanos-io/thanos/pkg/objstore/gcs/gcs.go index 533659dc284..ae2cf3202bb 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/objstore/gcs/gcs.go +++ b/vendor/github.com/thanos-io/thanos/pkg/objstore/gcs/gcs.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + // Package gcs implements common object storage abstractions against Google Cloud Storage. package gcs diff --git a/vendor/github.com/thanos-io/thanos/pkg/objstore/objstore.go b/vendor/github.com/thanos-io/thanos/pkg/objstore/objstore.go index 5a70d885dc4..e187be3c62b 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/objstore/objstore.go +++ b/vendor/github.com/thanos-io/thanos/pkg/objstore/objstore.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package objstore import ( @@ -316,8 +319,7 @@ func (b *metricBucket) Upload(ctx context.Context, name string, r io.Reader) err if err != nil { b.opsFailures.WithLabelValues(op).Inc() } else { - // TODO: Use SetToCurrentTime() once we update the Prometheus client_golang. - b.lastSuccessfullUploadTime.WithLabelValues(b.bkt.Name()).Set(float64(time.Now().UnixNano()) / 1e9) + b.lastSuccessfullUploadTime.WithLabelValues(b.bkt.Name()).SetToCurrentTime() } b.ops.WithLabelValues(op).Inc() b.opsDuration.WithLabelValues(op).Observe(time.Since(start).Seconds()) diff --git a/vendor/github.com/thanos-io/thanos/pkg/objstore/s3/s3.go b/vendor/github.com/thanos-io/thanos/pkg/objstore/s3/s3.go index 2ca9d187c43..d924eeb01f3 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/objstore/s3/s3.go +++ b/vendor/github.com/thanos-io/thanos/pkg/objstore/s3/s3.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + // Package s3 implements common object storage abstractions against s3-compatible APIs. package s3 diff --git a/vendor/github.com/thanos-io/thanos/pkg/objstore/testing.go b/vendor/github.com/thanos-io/thanos/pkg/objstore/testing.go index 18010aa5f33..9e9a864b915 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/objstore/testing.go +++ b/vendor/github.com/thanos-io/thanos/pkg/objstore/testing.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package objstore import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/pool/pool.go b/vendor/github.com/thanos-io/thanos/pkg/pool/pool.go index 9c4a2f22120..ede9e667bfa 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/pool/pool.go +++ b/vendor/github.com/thanos-io/thanos/pkg/pool/pool.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package pool import ( @@ -6,10 +9,15 @@ import ( "github.com/pkg/errors" ) -// BytesPool is a bucketed pool for variably sized byte slices. It can be configured to not allow +type BytesPool interface { + Get(sz int) (*[]byte, error) + Put(b *[]byte) +} + +// BucketedBytesPool is a bucketed pool for variably sized byte slices. It can be configured to not allow // more than a maximum number of bytes being used at a given time. // Every byte slice obtained from the pool must be returned. -type BytesPool struct { +type BucketedBytesPool struct { buckets []sync.Pool sizes []int maxTotal uint64 @@ -22,7 +30,7 @@ type BytesPool struct { // NewBytesPool returns a new BytesPool with size buckets for minSize to maxSize // increasing by the given factor and maximum number of used bytes. // No more than maxTotal bytes can be used at any given time unless maxTotal is set to 0. -func NewBytesPool(minSize, maxSize int, factor float64, maxTotal uint64) (*BytesPool, error) { +func NewBucketedBytesPool(minSize, maxSize int, factor float64, maxTotal uint64) (*BucketedBytesPool, error) { if minSize < 1 { return nil, errors.New("invalid minimum pool size") } @@ -38,7 +46,7 @@ func NewBytesPool(minSize, maxSize int, factor float64, maxTotal uint64) (*Bytes for s := minSize; s <= maxSize; s = int(float64(s) * factor) { sizes = append(sizes, s) } - p := &BytesPool{ + p := &BucketedBytesPool{ buckets: make([]sync.Pool, len(sizes)), sizes: sizes, maxTotal: maxTotal, @@ -54,7 +62,7 @@ func NewBytesPool(minSize, maxSize int, factor float64, maxTotal uint64) (*Bytes var ErrPoolExhausted = errors.New("pool exhausted") // Get returns a new byte slices that fits the given size. -func (p *BytesPool) Get(sz int) (*[]byte, error) { +func (p *BucketedBytesPool) Get(sz int) (*[]byte, error) { p.mtx.Lock() defer p.mtx.Unlock() @@ -81,7 +89,7 @@ func (p *BytesPool) Get(sz int) (*[]byte, error) { } // Put returns a byte slice to the right bucket in the pool. -func (p *BytesPool) Put(b *[]byte) { +func (p *BucketedBytesPool) Put(b *[]byte) { if b == nil { return } diff --git a/vendor/github.com/thanos-io/thanos/pkg/runutil/runutil.go b/vendor/github.com/thanos-io/thanos/pkg/runutil/runutil.go index e5f7fa2ef66..45d06f4e08f 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/runutil/runutil.go +++ b/vendor/github.com/thanos-io/thanos/pkg/runutil/runutil.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + // Package runutil provides helpers to advanced function scheduling control like repeat or retry. // // It's very often the case when you need to excutes some code every fixed intervals or have it retried automatically. diff --git a/vendor/github.com/thanos-io/thanos/pkg/shipper/shipper.go b/vendor/github.com/thanos-io/thanos/pkg/shipper/shipper.go index f06b4478c09..39e7d61d868 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/shipper/shipper.go +++ b/vendor/github.com/thanos-io/thanos/pkg/shipper/shipper.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + // Package shipper detects directories on the local file system and uploads // them to a block storage. package shipper @@ -39,7 +42,7 @@ func newMetrics(r prometheus.Registerer, uploadCompacted bool) *metrics { m.dirSyncs = prometheus.NewCounter(prometheus.CounterOpts{ Name: "thanos_shipper_dir_syncs_total", - Help: "Total dir sync attempts", + Help: "Total number of dir syncs", }) m.dirSyncFailures = prometheus.NewCounter(prometheus.CounterOpts{ Name: "thanos_shipper_dir_sync_failures_total", @@ -47,11 +50,11 @@ func newMetrics(r prometheus.Registerer, uploadCompacted bool) *metrics { }) m.uploads = prometheus.NewCounter(prometheus.CounterOpts{ Name: "thanos_shipper_uploads_total", - Help: "Total object upload attempts", + Help: "Total number of uploaded blocks", }) m.uploadFailures = prometheus.NewCounter(prometheus.CounterOpts{ Name: "thanos_shipper_upload_failures_total", - Help: "Total number of failed object uploads", + Help: "Total number of block upload failures", }) m.uploadedCompacted = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "thanos_shipper_upload_compacted_done", diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/bucket.go b/vendor/github.com/thanos-io/thanos/pkg/store/bucket.go index 835147a32de..0ce8f974028 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/bucket.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/bucket.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package store import ( @@ -24,6 +27,7 @@ import ( "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" + "github.com/prometheus/prometheus/tsdb/encoding" "github.com/prometheus/prometheus/tsdb/fileutil" "github.com/prometheus/prometheus/tsdb/index" "github.com/thanos-io/thanos/pkg/block" @@ -57,6 +61,8 @@ const ( maxChunkSize = 16000 + maxSeriesSize = 64 * 1024 + // CompatibilityTypeLabelName is an artificial label that Store Gateway can optionally advertise. This is required for compatibility // with pre v0.8.0 Querier. Previous Queriers was strict about duplicated external labels of all StoreAPIs that had any labels. // Now with newer Store Gateway advertising all the external labels it has access to, there was simple case where @@ -68,6 +74,8 @@ const ( // This label name is intentionally against Prometheus label style. // TODO(bwplotka): Remove it at some point. CompatibilityTypeLabelName = "@thanos_compatibility_store_type" + + partitionerMaxGapSize = 512 * 1024 ) type bucketStoreMetrics struct { @@ -87,6 +95,7 @@ type bucketStoreMetrics struct { chunkSizeBytes prometheus.Histogram queriesDropped prometheus.Counter queriesLimit prometheus.Gauge + seriesRefetches prometheus.Counter } func newBucketStoreMetrics(reg prometheus.Registerer) *bucketStoreMetrics { @@ -166,6 +175,10 @@ func newBucketStoreMetrics(reg prometheus.Registerer) *bucketStoreMetrics { Name: "thanos_bucket_store_queries_concurrent_max", Help: "Number of maximum concurrent queries.", }) + m.seriesRefetches = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "thanos_bucket_store_series_refetches_total", + Help: fmt.Sprintf("Total number of cases where %v bytes was not enough was to fetch series from index, resulting in refetch.", maxSeriesSize), + }) if reg != nil { reg.MustRegister( @@ -185,6 +198,7 @@ func newBucketStoreMetrics(reg prometheus.Registerer) *bucketStoreMetrics { m.chunkSizeBytes, m.queriesDropped, m.queriesLimit, + m.seriesRefetches, ) } return &m @@ -204,7 +218,7 @@ type BucketStore struct { fetcher block.MetadataFetcher dir string indexCache storecache.IndexCache - chunkPool *pool.BytesPool + chunkPool pool.BytesPool // Sets of blocks that have the same labels. They are indexed by a hash over their label set. mtx sync.RWMutex @@ -217,15 +231,16 @@ type BucketStore struct { blockSyncConcurrency int // Query gate which limits the maximum amount of concurrent queries. - queryGate *gate.Gate + queryGate gate.Gater // samplesLimiter limits the number of samples per each Series() call. - samplesLimiter *Limiter + samplesLimiter SampleLimiter partitioner partitioner filterConfig *FilterConfig advLabelSets []storepb.LabelSet enableCompatibilityLabel bool + enableIndexHeader bool } // NewBucketStore creates a new bucket backed store that implements the store API against @@ -244,6 +259,7 @@ func NewBucketStore( blockSyncConcurrency int, filterConfig *FilterConfig, enableCompatibilityLabel bool, + enableIndexHeader bool, ) (*BucketStore, error) { if logger == nil { logger = log.NewNopLogger() @@ -253,13 +269,11 @@ func NewBucketStore( return nil, errors.Errorf("max concurrency value cannot be lower than 0 (got %v)", maxConcurrent) } - chunkPool, err := pool.NewBytesPool(maxChunkSize, 50e6, 2, maxChunkPoolBytes) + chunkPool, err := pool.NewBucketedBytesPool(maxChunkSize, 50e6, 2, maxChunkPoolBytes) if err != nil { return nil, errors.Wrap(err, "create chunk pool") } - const maxGapSize = 512 * 1024 - metrics := newBucketStoreMetrics(reg) s := &BucketStore{ logger: logger, @@ -278,8 +292,9 @@ func NewBucketStore( extprom.WrapRegistererWithPrefix("thanos_bucket_store_series_", reg), ), samplesLimiter: NewLimiter(maxSampleCount, metrics.queriesDropped), - partitioner: gapBasedPartitioner{maxGapSize: maxGapSize}, + partitioner: gapBasedPartitioner{maxGapSize: partitionerMaxGapSize}, enableCompatibilityLabel: enableCompatibilityLabel, + enableIndexHeader: enableIndexHeader, } s.metrics = metrics @@ -298,10 +313,7 @@ func (s *BucketStore) Close() (err error) { defer s.mtx.Unlock() for _, b := range s.blocks { - if e := b.Close(); e != nil { - level.Warn(s.logger).Log("msg", "closing Bucket block failed", "err", err) - err = e - } + runutil.CloseWithErrCapture(&err, b, "closing Bucket Block") } return err } @@ -418,10 +430,6 @@ func (s *BucketStore) addBlock(ctx context.Context, meta *metadata.Meta) (err er dir := filepath.Join(s.dir, meta.ULID.String()) start := time.Now() - if err := os.MkdirAll(dir, os.ModePerm); err != nil { - return errors.Wrap(err, "create dir") - } - level.Debug(s.logger).Log("msg", "loading new block", "id", meta.ULID) defer func() { if err != nil { @@ -439,10 +447,23 @@ func (s *BucketStore) addBlock(ctx context.Context, meta *metadata.Meta) (err er lset := labels.FromMap(meta.Thanos.Labels) h := lset.Hash() - jr, err := indexheader.NewJSONReader(ctx, s.logger, s.bkt, s.dir, meta.ULID) - if err != nil { - return errors.Wrap(err, "create index header reader") + var indexHeaderReader indexheader.Reader + if s.enableIndexHeader { + indexHeaderReader, err = indexheader.NewBinaryReader(ctx, s.logger, s.bkt, s.dir, meta.ULID) + if err != nil { + return errors.Wrap(err, "create index header reader") + } + } else { + indexHeaderReader, err = indexheader.NewJSONReader(ctx, s.logger, s.bkt, s.dir, meta.ULID) + if err != nil { + return errors.Wrap(err, "create index cache reader") + } } + defer func() { + if err != nil { + runutil.CloseWithErrCapture(&err, indexHeaderReader, "index-header") + } + }() b, err := newBucketBlock( ctx, @@ -452,12 +473,19 @@ func (s *BucketStore) addBlock(ctx context.Context, meta *metadata.Meta) (err er dir, s.indexCache, s.chunkPool, - jr, + indexHeaderReader, s.partitioner, + s.metrics.seriesRefetches, ) if err != nil { return errors.Wrap(err, "new bucket block") } + defer func() { + if err != nil { + runutil.CloseWithErrCapture(&err, b, "index-header") + } + }() + s.mtx.Lock() defer s.mtx.Unlock() @@ -546,6 +574,10 @@ func (s *BucketStore) Info(context.Context, *storepb.InfoRequest) (*storepb.Info } func (s *BucketStore) limitMinTime(mint int64) int64 { + if s.filterConfig == nil { + return mint + } + filterMinTime := s.filterConfig.MinTime.PrometheusTimestamp() if mint < filterMinTime { @@ -556,6 +588,10 @@ func (s *BucketStore) limitMinTime(mint int64) int64 { } func (s *BucketStore) limitMaxTime(maxt int64) int64 { + if s.filterConfig == nil { + return maxt + } + filterMaxTime := s.filterConfig.MaxTime.PrometheusTimestamp() if maxt > filterMaxTime { @@ -601,14 +637,12 @@ func (s *bucketSeriesSet) Err() error { } func blockSeries( - ctx context.Context, - ulid ulid.ULID, extLset map[string]string, indexr *bucketIndexReader, chunkr *bucketChunkReader, matchers []*labels.Matcher, req *storepb.SeriesRequest, - samplesLimiter *Limiter, + samplesLimiter SampleLimiter, ) (storepb.SeriesSet, *queryStats, error) { ps, err := indexr.ExpandedPostings(matchers) if err != nil { @@ -822,6 +856,7 @@ func (s *BucketStore) Series(req *storepb.SeriesRequest, srv storepb.Store_Serie if !ok { continue } + blocks := bs.getFor(req.MinTime, req.MaxTime, req.MaxResolutionWindow) mtx.Lock() @@ -833,7 +868,6 @@ func (s *BucketStore) Series(req *storepb.SeriesRequest, srv storepb.Store_Serie } for _, b := range blocks { - b := b // We must keep the readers open until all their data has been sent. @@ -845,8 +879,7 @@ func (s *BucketStore) Series(req *storepb.SeriesRequest, srv storepb.Store_Serie defer runutil.CloseWithLogOnErr(s.logger, chunkr, "series block") g.Go(func() error { - part, pstats, err := blockSeries(ctx, - b.meta.ULID, + part, pstats, err := blockSeries( b.meta.Thanos.Labels, indexr, chunkr, @@ -999,7 +1032,10 @@ func (s *BucketStore) LabelValues(ctx context.Context, req *storepb.LabelValuesR defer runutil.CloseWithLogOnErr(s.logger, indexr, "label values") // Do it via index reader to have pending reader registered correctly. - res := indexr.block.indexHeaderReader.LabelValues(req.Label) + res, err := indexr.block.indexHeaderReader.LabelValues(req.Label) + if err != nil { + return errors.Wrap(err, "index header label values") + } mtx.Lock() sets = append(sets, res) @@ -1085,7 +1121,7 @@ func int64index(s []int64, x int64) int { // getFor returns a time-ordered list of blocks that cover date between mint and maxt. // Blocks with the biggest resolution possible but not bigger than the given max resolution are returned. func (s *bucketBlockSet) getFor(mint, maxt, maxResolutionMillis int64) (bs []*bucketBlock) { - if mint == maxt { + if mint > maxt { return nil } @@ -1098,20 +1134,23 @@ func (s *bucketBlockSet) getFor(mint, maxt, maxResolutionMillis int64) (bs []*bu } // Fill the given interval with the blocks for the current resolution. - // Our current resolution might not cover all data, so recursively fill the gaps with higher resolution blocks if there is any. + // Our current resolution might not cover all data, so recursively fill the gaps with higher resolution blocks + // if there is any. start := mint for _, b := range s.blocks[i] { if b.meta.MaxTime <= mint { continue } - if b.meta.MinTime >= maxt { + // NOTE: Block intervals are half-open: [b.MinTime, b.MaxTime). + if b.meta.MinTime > maxt { break } if i+1 < len(s.resolutions) { - bs = append(bs, s.getFor(start, b.meta.MinTime, s.resolutions[i+1])...) + bs = append(bs, s.getFor(start, b.meta.MinTime-1, s.resolutions[i+1])...) } bs = append(bs, b) + start = b.meta.MaxTime } @@ -1143,11 +1182,11 @@ func (s *bucketBlockSet) labelMatchers(matchers ...*labels.Matcher) ([]*labels.M // state for the block on local disk. type bucketBlock struct { logger log.Logger - bucket objstore.BucketReader + bkt objstore.BucketReader meta *metadata.Meta dir string indexCache storecache.IndexCache - chunkPool *pool.BytesPool + chunkPool pool.BytesPool indexHeaderReader indexheader.Reader @@ -1156,6 +1195,8 @@ type bucketBlock struct { pendingReaders sync.WaitGroup partitioner partitioner + + seriesRefetches prometheus.Counter } func newBucketBlock( @@ -1165,27 +1206,28 @@ func newBucketBlock( bkt objstore.BucketReader, dir string, indexCache storecache.IndexCache, - chunkPool *pool.BytesPool, + chunkPool pool.BytesPool, indexHeadReader indexheader.Reader, p partitioner, + seriesRefetches prometheus.Counter, ) (b *bucketBlock, err error) { b = &bucketBlock{ logger: logger, - bucket: bkt, + bkt: bkt, indexCache: indexCache, chunkPool: chunkPool, dir: dir, partitioner: p, meta: meta, indexHeaderReader: indexHeadReader, + seriesRefetches: seriesRefetches, } // Get object handles for all chunk files. - err = bkt.Iter(ctx, path.Join(meta.ULID.String(), block.ChunksDirname), func(n string) error { + if err = bkt.Iter(ctx, path.Join(meta.ULID.String(), block.ChunksDirname), func(n string) error { b.chunkObjs = append(b.chunkObjs, n) return nil - }) - if err != nil { + }); err != nil { return nil, errors.Wrap(err, "list chunk files") } return b, nil @@ -1196,7 +1238,7 @@ func (b *bucketBlock) indexFilename() string { } func (b *bucketBlock) readIndexRange(ctx context.Context, off, length int64) ([]byte, error) { - r, err := b.bucket.GetRange(ctx, b.indexFilename(), off, length) + r, err := b.bkt.GetRange(ctx, b.indexFilename(), off, length) if err != nil { return nil, errors.Wrap(err, "get range reader") } @@ -1216,7 +1258,7 @@ func (b *bucketBlock) readChunkRange(ctx context.Context, seq int, off, length i } buf := bytes.NewBuffer(*c) - r, err := b.bucket.GetRange(ctx, b.chunkObjs[seq], off, length) + r, err := b.bkt.GetRange(ctx, b.chunkObjs[seq], off, length) if err != nil { b.chunkPool.Put(c) return nil, errors.Wrap(err, "get range reader") @@ -1233,7 +1275,7 @@ func (b *bucketBlock) readChunkRange(ctx context.Context, seq int, off, length i func (b *bucketBlock) indexReader(ctx context.Context) *bucketIndexReader { b.pendingReaders.Add(1) - return newBucketIndexReader(ctx, b.logger, b, b.indexCache) + return newBucketIndexReader(ctx, b) } func (b *bucketBlock) chunkReader(ctx context.Context) *bucketChunkReader { @@ -1244,33 +1286,30 @@ func (b *bucketBlock) chunkReader(ctx context.Context) *bucketChunkReader { // Close waits for all pending readers to finish and then closes all underlying resources. func (b *bucketBlock) Close() error { b.pendingReaders.Wait() - return nil + + return b.indexHeaderReader.Close() } // bucketIndexReader is a custom index reader (not conforming index.Reader interface) that reads index that is stored in // object storage without having to fully download it. type bucketIndexReader struct { - logger log.Logger - ctx context.Context - block *bucketBlock - dec *index.Decoder - stats *queryStats - cache storecache.IndexCache + ctx context.Context + block *bucketBlock + dec *index.Decoder + stats *queryStats mtx sync.Mutex loadedSeries map[uint64][]byte } -func newBucketIndexReader(ctx context.Context, logger log.Logger, block *bucketBlock, cache storecache.IndexCache) *bucketIndexReader { +func newBucketIndexReader(ctx context.Context, block *bucketBlock) *bucketIndexReader { r := &bucketIndexReader{ - logger: logger, - ctx: ctx, - block: block, + ctx: ctx, + block: block, dec: &index.Decoder{ LookupSymbol: block.indexHeaderReader.LookupSymbol, }, stats: &queryStats{}, - cache: cache, loadedSeries: map[uint64][]byte{}, } return r @@ -1291,7 +1330,12 @@ func (r *bucketIndexReader) ExpandedPostings(ms []*labels.Matcher) ([]uint64, er // NOTE: Derived from tsdb.PostingsForMatchers. for _, m := range ms { // Each group is separate to tell later what postings are intersecting with what. - postingGroups = append(postingGroups, toPostingGroup(r.block.indexHeaderReader.LabelValues, m)) + pg, err := toPostingGroup(r.block.indexHeaderReader.LabelValues, m) + if err != nil { + return nil, errors.Wrap(err, "toPostingGroup") + } + + postingGroups = append(postingGroups, pg) } if len(postingGroups) == 0 { @@ -1366,7 +1410,7 @@ func allWithout(p []index.Postings) index.Postings { } // NOTE: Derived from tsdb.postingsForMatcher. index.Merge is equivalent to map duplication. -func toPostingGroup(lvalsFn func(name string) []string, m *labels.Matcher) *postingGroup { +func toPostingGroup(lvalsFn func(name string) ([]string, error), m *labels.Matcher) (*postingGroup, error) { var matchingLabels labels.Labels // If the matcher selects an empty value, it selects all the series which don't @@ -1376,7 +1420,11 @@ func toPostingGroup(lvalsFn func(name string) []string, m *labels.Matcher) *post allName, allValue := index.AllPostingsKey() matchingLabels = append(matchingLabels, labels.Label{Name: allName, Value: allValue}) - for _, val := range lvalsFn(m.Name) { + vals, err := lvalsFn(m.Name) + if err != nil { + return nil, err + } + for _, val := range vals { if !m.Matches(val) { matchingLabels = append(matchingLabels, labels.Label{Name: m.Name, Value: val}) } @@ -1386,24 +1434,29 @@ func toPostingGroup(lvalsFn func(name string) []string, m *labels.Matcher) *post // This is known hack to return all series. // Ask for x != . Allow for that as Prometheus does, // even though it is expensive. - return newPostingGroup(matchingLabels, merge) + return newPostingGroup(matchingLabels, merge), nil } - return newPostingGroup(matchingLabels, allWithout) + return newPostingGroup(matchingLabels, allWithout), nil } // Fast-path for equal matching. if m.Type == labels.MatchEqual { - return newPostingGroup(labels.Labels{{Name: m.Name, Value: m.Value}}, merge) + return newPostingGroup(labels.Labels{{Name: m.Name, Value: m.Value}}, merge), nil } - for _, val := range lvalsFn(m.Name) { + vals, err := lvalsFn(m.Name) + if err != nil { + return nil, err + } + + for _, val := range vals { if m.Matches(val) { matchingLabels = append(matchingLabels, labels.Label{Name: m.Name, Value: val}) } } - return newPostingGroup(matchingLabels, merge) + return newPostingGroup(matchingLabels, merge), nil } type postingPtr struct { @@ -1422,7 +1475,7 @@ func (r *bucketIndexReader) fetchPostings(groups []*postingGroup) error { keys = append(keys, g.keys...) } - fromCache, _ := r.cache.FetchMultiPostings(r.ctx, r.block.meta.ULID, keys) + fromCache, _ := r.block.indexCache.FetchMultiPostings(r.ctx, r.block.meta.ULID, keys) // Iterate over all groups and fetch posting from cache. // If we have a miss, mark key to be fetched in `ptrs` slice. @@ -1438,18 +1491,23 @@ func (r *bucketIndexReader) fetchPostings(groups []*postingGroup) error { if err != nil { return errors.Wrap(err, "decode postings") } + g.Fill(j, l) continue } // Cache miss; save pointer for actual posting in index stored in object store. - ptr := r.block.indexHeaderReader.PostingsOffset(key.Name, key.Value) - if ptr == indexheader.NotFoundRange { + ptr, err := r.block.indexHeaderReader.PostingsOffset(key.Name, key.Value) + if err == indexheader.NotFoundRangeErr { // This block does not have any posting for given key. g.Fill(j, index.EmptyPostings()) continue } + if err != nil { + return errors.Wrap(err, "index header PostingsOffset") + } + r.stats.postingsToFetch++ ptrs = append(ptrs, postingPtr{ptr: ptr, groupID: i, keyID: j}) } @@ -1484,28 +1542,29 @@ func (r *bucketIndexReader) fetchPostings(groups []*postingGroup) error { fetchTime := time.Since(begin) r.mtx.Lock() - defer r.mtx.Unlock() - r.stats.postingsFetchCount++ r.stats.postingsFetched += j - i r.stats.postingsFetchDurationSum += fetchTime r.stats.postingsFetchedSizeSum += int(length) + r.mtx.Unlock() for _, p := range ptrs[i:j] { - c := b[p.ptr.Start-start : p.ptr.End-start] - - _, fetchedPostings, err := r.dec.Postings(c) + // index-header can estimate endings, which means we need to resize the endings. + pBytes, err := resizePostings(b[p.ptr.Start-start : p.ptr.End-start]) if err != nil { - return errors.Wrap(err, "read postings list") + return err } + r.mtx.Lock() // Return postings and fill LRU cache. - groups[p.groupID].Fill(p.keyID, fetchedPostings) - r.cache.StorePostings(r.ctx, r.block.meta.ULID, groups[p.groupID].keys[p.keyID], c) + // Truncate first 4 bytes which are length of posting. + groups[p.groupID].Fill(p.keyID, newBigEndianPostings(pBytes[4:])) + r.block.indexCache.StorePostings(r.ctx, r.block.meta.ULID, groups[p.groupID].keys[p.keyID], pBytes) // If we just fetched it we still have to update the stats for touched postings. r.stats.postingsTouched++ - r.stats.postingsTouchedSizeSum += len(c) + r.stats.postingsTouchedSizeSum += len(pBytes) + r.mtx.Unlock() } return nil }) @@ -1514,12 +1573,74 @@ func (r *bucketIndexReader) fetchPostings(groups []*postingGroup) error { return g.Wait() } -func (r *bucketIndexReader) PreloadSeries(ids []uint64) error { - const maxSeriesSize = 64 * 1024 +func resizePostings(b []byte) ([]byte, error) { + d := encoding.Decbuf{B: b} + n := d.Be32int() + if d.Err() != nil { + return nil, errors.Wrap(d.Err(), "read postings list") + } + + // 4 for postings number of entries, then 4, foreach each big endian posting. + size := 4 + n*4 + if len(b) < size { + return nil, encoding.ErrInvalidSize + } + return b[:size], nil +} + +// bigEndianPostings implements the Postings interface over a byte stream of +// big endian numbers. +type bigEndianPostings struct { + list []byte + cur uint32 +} + +// TODO(bwplotka): Expose those inside Prometheus. +func newBigEndianPostings(list []byte) *bigEndianPostings { + return &bigEndianPostings{list: list} +} + +func (it *bigEndianPostings) At() uint64 { + return uint64(it.cur) +} + +func (it *bigEndianPostings) Next() bool { + if len(it.list) >= 4 { + it.cur = binary.BigEndian.Uint32(it.list) + it.list = it.list[4:] + return true + } + return false +} +func (it *bigEndianPostings) Seek(x uint64) bool { + if uint64(it.cur) >= x { + return true + } + + num := len(it.list) / 4 + // Do binary search between current position and end. + i := sort.Search(num, func(i int) bool { + return binary.BigEndian.Uint32(it.list[i*4:]) >= uint32(x) + }) + if i < num { + j := i * 4 + it.cur = binary.BigEndian.Uint32(it.list[j:]) + it.list = it.list[j+4:] + return true + } + it.list = nil + return false +} + +func (it *bigEndianPostings) Err() error { + return nil +} + +func (r *bucketIndexReader) PreloadSeries(ids []uint64) error { // Load series from cache, overwriting the list of ids to preload // with the missing ones. - fromCache, ids := r.cache.FetchMultiSeries(r.ctx, r.block.meta.ULID, ids) + fromCache, ids := r.block.indexCache.FetchMultiSeries(r.ctx, r.block.meta.ULID, ids) for id, b := range fromCache { r.loadedSeries[id] = b } @@ -1533,13 +1654,13 @@ func (r *bucketIndexReader) PreloadSeries(ids []uint64) error { i, j := p.elemRng[0], p.elemRng[1] g.Go(func() error { - return r.loadSeries(ctx, ids[i:j], s, e) + return r.loadSeries(ctx, ids[i:j], false, s, e) }) } return g.Wait() } -func (r *bucketIndexReader) loadSeries(ctx context.Context, ids []uint64, start, end uint64) error { +func (r *bucketIndexReader) loadSeries(ctx context.Context, ids []uint64, refetch bool, start, end uint64) error { begin := time.Now() b, err := r.block.readIndexRange(ctx, int64(start), int64(end-start)) @@ -1548,14 +1669,13 @@ func (r *bucketIndexReader) loadSeries(ctx context.Context, ids []uint64, start, } r.mtx.Lock() - defer r.mtx.Unlock() - r.stats.seriesFetchCount++ r.stats.seriesFetched += len(ids) r.stats.seriesFetchDurationSum += time.Since(begin) r.stats.seriesFetchedSizeSum += int(end - start) + r.mtx.Unlock() - for _, id := range ids { + for i, id := range ids { c := b[id-start:] l, n := binary.Uvarint(c) @@ -1563,11 +1683,22 @@ func (r *bucketIndexReader) loadSeries(ctx context.Context, ids []uint64, start, return errors.New("reading series length failed") } if len(c) < n+int(l) { - return errors.Errorf("invalid remaining size %d, expected %d", len(c), n+int(l)) + if i == 0 && refetch { + return errors.Errorf("invalid remaining size, even after refetch, remaining: %d, expected %d", len(c), n+int(l)) + } + + // Inefficient, but should be rare. + r.block.seriesRefetches.Inc() + level.Warn(r.block.logger).Log("msg", "series size exceeded expected size; refetching", "id", id, "series length", n+int(l), "maxSeriesSize", maxSeriesSize) + + // Fetch plus to get the size of next one if exists. + return r.loadSeries(ctx, ids[i:], true, id, id+uint64(n+int(l)+1)) } c = c[n : n+int(l)] + r.mtx.Lock() r.loadedSeries[id] = c - r.cache.StoreSeries(r.ctx, r.block.meta.ULID, id, c) + r.block.indexCache.StoreSeries(r.ctx, r.block.meta.ULID, id, c) + r.mtx.Unlock() } return nil } @@ -1583,7 +1714,7 @@ type partitioner interface { // Partition partitions length entries into n <= length ranges that cover all // input ranges // It supports overlapping ranges. - // NOTE: It expects range to be sorted by start time. + // NOTE: It expects range to be ted by start time. Partition(length int, rng func(int) (uint64, uint64)) []part } @@ -1680,7 +1811,7 @@ func (r *bucketChunkReader) addPreload(id uint64) error { } // preload all added chunk IDs. Must be called before the first call to Chunk is made. -func (r *bucketChunkReader) preload(samplesLimiter *Limiter) error { +func (r *bucketChunkReader) preload(samplesLimiter SampleLimiter) error { g, ctx := errgroup.WithContext(r.ctx) numChunks := uint64(0) diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/cache/cache.go b/vendor/github.com/thanos-io/thanos/pkg/store/cache/cache.go index d7e175da823..2973de7b22f 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/cache/cache.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/cache/cache.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package storecache import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/cache/factory.go b/vendor/github.com/thanos-io/thanos/pkg/store/cache/factory.go index 7fed27dac2a..e67251d3c76 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/cache/factory.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/cache/factory.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package storecache import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/cache/inmemory.go b/vendor/github.com/thanos-io/thanos/pkg/store/cache/inmemory.go index 3b8881eb651..739d73b5bbd 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/cache/inmemory.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/cache/inmemory.go @@ -1,9 +1,14 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package storecache import ( "context" "math" + "reflect" "sync" + "unsafe" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" @@ -266,15 +271,29 @@ func (c *InMemoryIndexCache) reset() { c.curSize = 0 } +func copyString(s string) string { + var b []byte + h := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + h.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data + h.Len = len(s) + h.Cap = len(s) + return string(b) +} + +// copyToKey is required as underlying strings might be mmaped. +func copyToKey(l labels.Label) cacheKeyPostings { + return cacheKeyPostings(labels.Label{Value: copyString(l.Value), Name: copyString(l.Name)}) +} + // StorePostings sets the postings identified by the ulid and label to the value v, // if the postings already exists in the cache it is not mutated. -func (c *InMemoryIndexCache) StorePostings(ctx context.Context, blockID ulid.ULID, l labels.Label, v []byte) { - c.set(cacheTypePostings, cacheKey{blockID, cacheKeyPostings(l)}, v) +func (c *InMemoryIndexCache) StorePostings(_ context.Context, blockID ulid.ULID, l labels.Label, v []byte) { + c.set(cacheTypePostings, cacheKey{block: blockID, key: copyToKey(l)}, v) } // FetchMultiPostings fetches multiple postings - each identified by a label - // and returns a map containing cache hits, along with a list of missing keys. -func (c *InMemoryIndexCache) FetchMultiPostings(ctx context.Context, blockID ulid.ULID, keys []labels.Label) (hits map[labels.Label][]byte, misses []labels.Label) { +func (c *InMemoryIndexCache) FetchMultiPostings(_ context.Context, blockID ulid.ULID, keys []labels.Label) (hits map[labels.Label][]byte, misses []labels.Label) { hits = map[labels.Label][]byte{} for _, key := range keys { @@ -291,13 +310,13 @@ func (c *InMemoryIndexCache) FetchMultiPostings(ctx context.Context, blockID uli // StoreSeries sets the series identified by the ulid and id to the value v, // if the series already exists in the cache it is not mutated. -func (c *InMemoryIndexCache) StoreSeries(ctx context.Context, blockID ulid.ULID, id uint64, v []byte) { +func (c *InMemoryIndexCache) StoreSeries(_ context.Context, blockID ulid.ULID, id uint64, v []byte) { c.set(cacheTypeSeries, cacheKey{blockID, cacheKeySeries(id)}, v) } // FetchMultiSeries fetches multiple series - each identified by ID - from the cache // and returns a map containing cache hits, along with a list of missing IDs. -func (c *InMemoryIndexCache) FetchMultiSeries(ctx context.Context, blockID ulid.ULID, ids []uint64) (hits map[uint64][]byte, misses []uint64) { +func (c *InMemoryIndexCache) FetchMultiSeries(_ context.Context, blockID ulid.ULID, ids []uint64) (hits map[uint64][]byte, misses []uint64) { hits = map[uint64][]byte{} for _, id := range ids { diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/cache/memcached.go b/vendor/github.com/thanos-io/thanos/pkg/store/cache/memcached.go index 51c028dd54a..db7ec61c635 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/cache/memcached.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/cache/memcached.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package storecache import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/cache/units.go b/vendor/github.com/thanos-io/thanos/pkg/store/cache/units.go index d9b6dce3679..156ea54ddbd 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/cache/units.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/cache/units.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package storecache import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/limiter.go b/vendor/github.com/thanos-io/thanos/pkg/store/limiter.go index 2c332a2c6b2..5c23752d73e 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/limiter.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/limiter.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package store import ( @@ -5,6 +8,10 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +type SampleLimiter interface { + Check(num uint64) error +} + // Limiter is a simple mechanism for checking if something has passed a certain threshold. type Limiter struct { limit uint64 diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/matchers.go b/vendor/github.com/thanos-io/thanos/pkg/store/matchers.go index 66902f51165..18abe0fba19 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/matchers.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/matchers.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package store import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/prometheus.go b/vendor/github.com/thanos-io/thanos/pkg/store/prometheus.go index 41fa52e3e6d..ed32b389b59 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/prometheus.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/prometheus.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package store import ( @@ -12,8 +15,10 @@ import ( "net/url" "path" "sort" + "strconv" "strings" "sync" + "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" @@ -23,6 +28,7 @@ import ( "github.com/pkg/errors" "github.com/prometheus/common/version" "github.com/prometheus/prometheus/pkg/labels" + "github.com/prometheus/prometheus/pkg/timestamp" "github.com/prometheus/prometheus/prompb" "github.com/prometheus/prometheus/storage/remote" "github.com/prometheus/prometheus/tsdb/chunkenc" @@ -426,6 +432,11 @@ func (p *PrometheusStore) startPromSeries(ctx context.Context, q *prompb.Query) return nil, errors.Wrap(err, "marshal read request") } + qjson, err := json.Marshal(q) + if err != nil { + return nil, errors.Wrap(err, "json encode query for tracing") + } + u := *p.base u.Path = path.Join(u.Path, "api/v1/read") @@ -436,13 +447,13 @@ func (p *PrometheusStore) startPromSeries(ctx context.Context, q *prompb.Query) preq.Header.Add("Content-Encoding", "snappy") preq.Header.Set("Content-Type", "application/x-stream-protobuf") preq.Header.Set("User-Agent", userAgent) - spanReqDo, ctx := tracing.StartSpan(ctx, "query_prometheus_request") + spanReqDo, ctx := tracing.StartSpan(ctx, "query_prometheus_request", opentracing.Tag{Key: "prometheus.query", Value: string(qjson)}) preq = preq.WithContext(ctx) presp, err := p.client.Do(preq) + spanReqDo.Finish() if err != nil { return nil, errors.Wrap(err, "send request") } - spanReqDo.Finish() if presp.StatusCode/100 != 2 { // Best effort read. b, err := ioutil.ReadAll(presp.Body) @@ -663,9 +674,9 @@ func (p *PrometheusStore) seriesLabels(ctx context.Context, matchers []storepb.L } q.Add("match[]", metric) + q.Add("start", formatTime(timestamp.Time(startTime))) + q.Add("end", formatTime(timestamp.Time(endTime))) u.RawQuery = q.Encode() - q.Add("start", string(startTime)) - q.Add("end", string(endTime)) req, err := http.NewRequest("GET", u.String(), nil) if err != nil { @@ -715,3 +726,7 @@ func (p *PrometheusStore) seriesLabels(ctx context.Context, matchers []storepb.L return m.Data, nil } + +func formatTime(t time.Time) string { + return strconv.FormatFloat(float64(t.Unix())+float64(t.Nanosecond())/1e9, 'f', -1, 64) +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/proxy.go b/vendor/github.com/thanos-io/thanos/pkg/store/proxy.go index 574c5e0e4b1..974a25215d9 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/proxy.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/proxy.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package store import ( @@ -15,6 +18,7 @@ import ( grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing" "github.com/opentracing/opentracing-go" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/prometheus/pkg/labels" "github.com/thanos-io/thanos/pkg/component" "github.com/thanos-io/thanos/pkg/store/storepb" @@ -49,12 +53,34 @@ type ProxyStore struct { selectorLabels labels.Labels responseTimeout time.Duration + metrics *proxyStoreMetrics +} + +type proxyStoreMetrics struct { + emptyStreamResponses prometheus.Counter +} + +func newProxyStoreMetrics(reg prometheus.Registerer) *proxyStoreMetrics { + var m proxyStoreMetrics + + m.emptyStreamResponses = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "thanos_proxy_store_empty_stream_responses_total", + Help: "Total number of empty responses received.", + }) + + if reg != nil { + reg.MustRegister( + m.emptyStreamResponses, + ) + } + return &m } // NewProxyStore returns a new ProxyStore that uses the given clients that implements storeAPI to fan-in all series to the client. // Note that there is no deduplication support. Deduplication should be done on the highest level (just before PromQL). func NewProxyStore( logger log.Logger, + reg prometheus.Registerer, stores func() []Client, component component.StoreAPI, selectorLabels labels.Labels, @@ -64,12 +90,14 @@ func NewProxyStore( logger = log.NewNopLogger() } + metrics := newProxyStoreMetrics(reg) s := &ProxyStore{ logger: logger, stores: stores, component: component, selectorLabels: selectorLabels, responseTimeout: responseTimeout, + metrics: metrics, } return s } @@ -170,12 +198,7 @@ func newRespCh(ctx context.Context, buffer int) (*ctxRespSender, <-chan *storepb } func (s ctxRespSender) send(r *storepb.SeriesResponse) { - select { - case <-s.ctx.Done(): - return - case s.ch <- r: - return - } + s.ch <- r } // Series returns all series for a requested time range and label matcher. Requested series are taken from other @@ -260,13 +283,13 @@ func (s *ProxyStore) Series(r *storepb.SeriesRequest, srv storepb.Store_SeriesSe // Schedule streamSeriesSet that translates gRPC streamed response // into seriesSet (if series) or respCh if warnings. seriesSet = append(seriesSet, startStreamSeriesSet(seriesCtx, s.logger, closeSeries, - wg, sc, respSender, st.String(), !r.PartialResponseDisabled, s.responseTimeout)) + wg, sc, respSender, st.String(), !r.PartialResponseDisabled, s.responseTimeout, s.metrics.emptyStreamResponses)) } level.Debug(s.logger).Log("msg", strings.Join(storeDebugMsgs, ";")) if len(seriesSet) == 0 { // This is indicates that configured StoreAPIs are not the ones end user expects. - err := errors.New("No store matched for this query") + err := errors.New("No StoreAPIs matched for this query") level.Warn(s.logger).Log("err", err, "stores", strings.Join(storeDebugMsgs, ";")) respSender.send(storepb.NewWarnSeriesResponse(err)) return nil @@ -320,6 +343,21 @@ type streamSeriesSet struct { closeSeries context.CancelFunc } +type recvResponse struct { + r *storepb.SeriesResponse + err error +} + +func frameCtx(responseTimeout time.Duration) (context.Context, context.CancelFunc) { + frameTimeoutCtx := context.Background() + var cancel context.CancelFunc + if responseTimeout != 0 { + frameTimeoutCtx, cancel = context.WithTimeout(frameTimeoutCtx, responseTimeout) + return frameTimeoutCtx, cancel + } + return frameTimeoutCtx, func() {} +} + func startStreamSeriesSet( ctx context.Context, logger log.Logger, @@ -330,6 +368,7 @@ func startStreamSeriesSet( name string, partialResponse bool, responseTimeout time.Duration, + emptyStreamResponses prometheus.Counter, ) *streamSeriesSet { s := &streamSeriesSet{ ctx: ctx, @@ -348,76 +387,79 @@ func startStreamSeriesSet( defer wg.Done() defer close(s.recvCh) - for { - r, err := s.stream.Recv() - - if err == io.EOF { - return + numResponses := 0 + defer func() { + if numResponses == 0 { + emptyStreamResponses.Inc() } + }() - if err != nil { - wrapErr := errors.Wrapf(err, "receive series from %s", s.name) - if partialResponse { - s.warnCh.send(storepb.NewWarnSeriesResponse(wrapErr)) + rCh := make(chan *recvResponse) + done := make(chan struct{}) + go func() { + for { + r, err := s.stream.Recv() + select { + case <-done: + close(rCh) return + case rCh <- &recvResponse{r: r, err: err}: } - - s.errMtx.Lock() - s.err = wrapErr - s.errMtx.Unlock() + } + }() + for { + frameTimeoutCtx, cancel := frameCtx(s.responseTimeout) + defer cancel() + var rr *recvResponse + select { + case <-ctx.Done(): + s.handleErr(errors.Wrapf(ctx.Err(), "failed to receive any data from %s", s.name), done) return + case <-frameTimeoutCtx.Done(): + s.handleErr(errors.Wrapf(frameTimeoutCtx.Err(), "failed to receive any data in %s from %s", s.responseTimeout.String(), s.name), done) + return + case rr = <-rCh: } - if w := r.GetWarning(); w != "" { - s.warnCh.send(storepb.NewWarnSeriesResponse(errors.New(w))) - continue + if rr.err == io.EOF { + close(done) + return } - select { - case s.recvCh <- r.GetSeries(): - continue - case <-ctx.Done(): + if rr.err != nil { + s.handleErr(errors.Wrapf(rr.err, "receive series from %s", s.name), done) return } + numResponses++ + if w := rr.r.GetWarning(); w != "" { + s.warnCh.send(storepb.NewWarnSeriesResponse(errors.New(w))) + continue + } + s.recvCh <- rr.r.GetSeries() } }() return s } -// Next blocks until new message is received or stream is closed or operation is timed out. -func (s *streamSeriesSet) Next() (ok bool) { - ctx := s.ctx - timeoutMsg := fmt.Sprintf("failed to receive any data from %s", s.name) - - if s.responseTimeout != 0 { - timeoutMsg = fmt.Sprintf("failed to receive any data in %s from %s", s.responseTimeout.String(), s.name) +func (s *streamSeriesSet) handleErr(err error, done chan struct{}) { + defer close(done) + s.closeSeries() - timeoutCtx, done := context.WithTimeout(s.ctx, s.responseTimeout) - defer done() - ctx = timeoutCtx + if s.partialResponse { + level.Warn(s.logger).Log("err", err, "msg", "returning partial response") + s.warnCh.send(storepb.NewWarnSeriesResponse(err)) + return } + s.errMtx.Lock() + s.err = err + s.errMtx.Unlock() +} - select { - case s.currSeries, ok = <-s.recvCh: - return ok - case <-ctx.Done(): - // closeSeries to shutdown a goroutine in startStreamSeriesSet. - s.closeSeries() - - err := errors.Wrap(ctx.Err(), timeoutMsg) - if s.partialResponse { - level.Warn(s.logger).Log("err", err, "msg", "returning partial response") - s.warnCh.send(storepb.NewWarnSeriesResponse(err)) - return false - } - s.errMtx.Lock() - s.err = err - s.errMtx.Unlock() - - level.Warn(s.logger).Log("err", err, "msg", "partial response disabled; aborting request") - return false - } +// Next blocks until new message is received or stream is closed or operation is timed out. +func (s *streamSeriesSet) Next() (ok bool) { + s.currSeries, ok = <-s.recvCh + return ok } func (s *streamSeriesSet) At() ([]storepb.Label, []storepb.AggrChunk) { diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/storepb/custom.go b/vendor/github.com/thanos-io/thanos/pkg/store/storepb/custom.go index c942dd13555..ea13089be43 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/storepb/custom.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/storepb/custom.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package storepb import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/storepb/rpc.pb.go b/vendor/github.com/thanos-io/thanos/pkg/store/storepb/rpc.pb.go index 77b5b5fa036..63f1ab4974e 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/storepb/rpc.pb.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/storepb/rpc.pb.go @@ -12,6 +12,7 @@ import ( _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + prompb "github.com/prometheus/prometheus/prompb" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -136,6 +137,81 @@ func (Aggr) EnumDescriptor() ([]byte, []int) { return fileDescriptor_77a6da22d6a3feb1, []int{2} } +type WriteResponse struct { +} + +func (m *WriteResponse) Reset() { *m = WriteResponse{} } +func (m *WriteResponse) String() string { return proto.CompactTextString(m) } +func (*WriteResponse) ProtoMessage() {} +func (*WriteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_77a6da22d6a3feb1, []int{0} +} +func (m *WriteResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WriteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WriteResponse.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 *WriteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_WriteResponse.Merge(m, src) +} +func (m *WriteResponse) XXX_Size() int { + return m.Size() +} +func (m *WriteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_WriteResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_WriteResponse proto.InternalMessageInfo + +type WriteRequest struct { + Timeseries []prompb.TimeSeries `protobuf:"bytes,1,rep,name=timeseries,proto3" json:"timeseries"` + Tenant string `protobuf:"bytes,2,opt,name=tenant,proto3" json:"tenant,omitempty"` + Replica int64 `protobuf:"varint,3,opt,name=replica,proto3" json:"replica,omitempty"` +} + +func (m *WriteRequest) Reset() { *m = WriteRequest{} } +func (m *WriteRequest) String() string { return proto.CompactTextString(m) } +func (*WriteRequest) ProtoMessage() {} +func (*WriteRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_77a6da22d6a3feb1, []int{1} +} +func (m *WriteRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WriteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WriteRequest.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 *WriteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WriteRequest.Merge(m, src) +} +func (m *WriteRequest) XXX_Size() int { + return m.Size() +} +func (m *WriteRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WriteRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_WriteRequest proto.InternalMessageInfo + type InfoRequest struct { } @@ -143,7 +219,7 @@ func (m *InfoRequest) Reset() { *m = InfoRequest{} } func (m *InfoRequest) String() string { return proto.CompactTextString(m) } func (*InfoRequest) ProtoMessage() {} func (*InfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{0} + return fileDescriptor_77a6da22d6a3feb1, []int{2} } func (m *InfoRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -186,7 +262,7 @@ func (m *InfoResponse) Reset() { *m = InfoResponse{} } func (m *InfoResponse) String() string { return proto.CompactTextString(m) } func (*InfoResponse) ProtoMessage() {} func (*InfoResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{1} + return fileDescriptor_77a6da22d6a3feb1, []int{3} } func (m *InfoResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -223,7 +299,7 @@ func (m *LabelSet) Reset() { *m = LabelSet{} } func (m *LabelSet) String() string { return proto.CompactTextString(m) } func (*LabelSet) ProtoMessage() {} func (*LabelSet) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{2} + return fileDescriptor_77a6da22d6a3feb1, []int{4} } func (m *LabelSet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -270,7 +346,7 @@ func (m *SeriesRequest) Reset() { *m = SeriesRequest{} } func (m *SeriesRequest) String() string { return proto.CompactTextString(m) } func (*SeriesRequest) ProtoMessage() {} func (*SeriesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{3} + return fileDescriptor_77a6da22d6a3feb1, []int{5} } func (m *SeriesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -310,7 +386,7 @@ func (m *SeriesResponse) Reset() { *m = SeriesResponse{} } func (m *SeriesResponse) String() string { return proto.CompactTextString(m) } func (*SeriesResponse) ProtoMessage() {} func (*SeriesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{4} + return fileDescriptor_77a6da22d6a3feb1, []int{6} } func (m *SeriesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -394,7 +470,7 @@ func (m *LabelNamesRequest) Reset() { *m = LabelNamesRequest{} } func (m *LabelNamesRequest) String() string { return proto.CompactTextString(m) } func (*LabelNamesRequest) ProtoMessage() {} func (*LabelNamesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{5} + return fileDescriptor_77a6da22d6a3feb1, []int{7} } func (m *LabelNamesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -432,7 +508,7 @@ func (m *LabelNamesResponse) Reset() { *m = LabelNamesResponse{} } func (m *LabelNamesResponse) String() string { return proto.CompactTextString(m) } func (*LabelNamesResponse) ProtoMessage() {} func (*LabelNamesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{6} + return fileDescriptor_77a6da22d6a3feb1, []int{8} } func (m *LabelNamesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -472,7 +548,7 @@ func (m *LabelValuesRequest) Reset() { *m = LabelValuesRequest{} } func (m *LabelValuesRequest) String() string { return proto.CompactTextString(m) } func (*LabelValuesRequest) ProtoMessage() {} func (*LabelValuesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{7} + return fileDescriptor_77a6da22d6a3feb1, []int{9} } func (m *LabelValuesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -510,7 +586,7 @@ func (m *LabelValuesResponse) Reset() { *m = LabelValuesResponse{} } func (m *LabelValuesResponse) String() string { return proto.CompactTextString(m) } func (*LabelValuesResponse) ProtoMessage() {} func (*LabelValuesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{8} + return fileDescriptor_77a6da22d6a3feb1, []int{10} } func (m *LabelValuesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -543,6 +619,8 @@ func init() { proto.RegisterEnum("thanos.StoreType", StoreType_name, StoreType_value) proto.RegisterEnum("thanos.PartialResponseStrategy", PartialResponseStrategy_name, PartialResponseStrategy_value) proto.RegisterEnum("thanos.Aggr", Aggr_name, Aggr_value) + proto.RegisterType((*WriteResponse)(nil), "thanos.WriteResponse") + proto.RegisterType((*WriteRequest)(nil), "thanos.WriteRequest") proto.RegisterType((*InfoRequest)(nil), "thanos.InfoRequest") proto.RegisterType((*InfoResponse)(nil), "thanos.InfoResponse") proto.RegisterType((*LabelSet)(nil), "thanos.LabelSet") @@ -557,58 +635,66 @@ func init() { func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) } var fileDescriptor_77a6da22d6a3feb1 = []byte{ - // 814 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x4f, 0x6f, 0xe3, 0x44, - 0x14, 0xf7, 0xd8, 0x89, 0x13, 0xbf, 0x6c, 0x2b, 0xef, 0x34, 0xbb, 0xeb, 0x1a, 0x29, 0xad, 0x2c, - 0x21, 0x45, 0x05, 0x65, 0x21, 0x08, 0x10, 0xdc, 0x92, 0xac, 0x57, 0x1b, 0xb1, 0x4d, 0x60, 0x92, - 0x6c, 0xf8, 0x73, 0x08, 0x4e, 0x3b, 0xb8, 0xd6, 0x3a, 0xb6, 0xf1, 0x38, 0xb4, 0xbd, 0xf2, 0x09, - 0xb8, 0xf2, 0x1d, 0xf8, 0x16, 0x5c, 0x7a, 0xdc, 0x23, 0x5c, 0x10, 0xb4, 0x5f, 0x04, 0x79, 0x3c, - 0x4e, 0x62, 0x68, 0x2b, 0xad, 0x72, 0x9b, 0xf7, 0xfb, 0xbd, 0x79, 0x6f, 0xde, 0xef, 0xbd, 0x99, - 0x01, 0x2d, 0x8e, 0x4e, 0x5a, 0x51, 0x1c, 0x26, 0x21, 0x56, 0x93, 0x33, 0x27, 0x08, 0x99, 0x59, - 0x4b, 0x2e, 0x23, 0xca, 0x32, 0xd0, 0xac, 0xbb, 0xa1, 0x1b, 0xf2, 0xe5, 0xd3, 0x74, 0x95, 0xa1, - 0xd6, 0x0e, 0xd4, 0xfa, 0xc1, 0x0f, 0x21, 0xa1, 0x3f, 0x2e, 0x29, 0x4b, 0xac, 0x3f, 0x11, 0x3c, - 0xc8, 0x6c, 0x16, 0x85, 0x01, 0xa3, 0xf8, 0x3d, 0x50, 0x7d, 0x67, 0x4e, 0x7d, 0x66, 0xa0, 0x43, - 0xa5, 0x59, 0x6b, 0xef, 0xb4, 0xb2, 0xd8, 0xad, 0x97, 0x29, 0xda, 0x2d, 0x5d, 0xfd, 0x75, 0x20, - 0x11, 0xe1, 0x82, 0xf7, 0xa1, 0xba, 0xf0, 0x82, 0x59, 0xe2, 0x2d, 0xa8, 0x21, 0x1f, 0xa2, 0xa6, - 0x42, 0x2a, 0x0b, 0x2f, 0x18, 0x7b, 0x0b, 0xca, 0x29, 0xe7, 0x22, 0xa3, 0x14, 0x41, 0x39, 0x17, - 0x9c, 0x7a, 0x0a, 0x1a, 0x4b, 0xc2, 0x98, 0x8e, 0x2f, 0x23, 0x6a, 0x94, 0x0e, 0x51, 0x73, 0xb7, - 0xfd, 0x30, 0xcf, 0x32, 0xca, 0x09, 0xb2, 0xf6, 0xc1, 0x1f, 0x03, 0xf0, 0x84, 0x33, 0x46, 0x13, - 0x66, 0x94, 0xf9, 0xb9, 0xf4, 0xc2, 0xb9, 0x46, 0x34, 0x11, 0x47, 0xd3, 0x7c, 0x61, 0x33, 0xeb, - 0x53, 0xa8, 0xe6, 0xe4, 0x5b, 0x95, 0x65, 0xfd, 0xaa, 0xc0, 0xce, 0x88, 0xc6, 0x1e, 0x65, 0x42, - 0xa6, 0x42, 0xa1, 0xe8, 0xee, 0x42, 0xe5, 0x62, 0xa1, 0x9f, 0xa4, 0x54, 0x72, 0x72, 0x46, 0x63, - 0x66, 0x28, 0x3c, 0x6d, 0xbd, 0x90, 0xf6, 0x38, 0x23, 0x45, 0xf6, 0x95, 0x2f, 0x6e, 0xc3, 0xa3, - 0x34, 0x64, 0x4c, 0x59, 0xe8, 0x2f, 0x13, 0x2f, 0x0c, 0x66, 0xe7, 0x5e, 0x70, 0x1a, 0x9e, 0x73, - 0xb1, 0x14, 0xb2, 0xb7, 0x70, 0x2e, 0xc8, 0x8a, 0x9b, 0x72, 0x0a, 0xbf, 0x0f, 0xe0, 0xb8, 0x6e, - 0x4c, 0x5d, 0x27, 0xa1, 0x99, 0x46, 0xbb, 0xed, 0x07, 0x79, 0xb6, 0x8e, 0xeb, 0xc6, 0x64, 0x83, - 0xc7, 0x9f, 0xc3, 0x7e, 0xe4, 0xc4, 0x89, 0xe7, 0xf8, 0x69, 0x16, 0xde, 0xf9, 0xd9, 0xa9, 0xc7, - 0x9c, 0xb9, 0x4f, 0x4f, 0x0d, 0xf5, 0x10, 0x35, 0xab, 0xe4, 0x89, 0x70, 0xc8, 0x27, 0xe3, 0x99, - 0xa0, 0xf1, 0x77, 0xb7, 0xec, 0x65, 0x49, 0xec, 0x24, 0xd4, 0xbd, 0x34, 0x2a, 0xbc, 0x9d, 0x07, - 0x79, 0xe2, 0x2f, 0x8b, 0x31, 0x46, 0xc2, 0xed, 0x7f, 0xc1, 0x73, 0x02, 0x1f, 0x40, 0x8d, 0xbd, - 0xf6, 0xa2, 0xd9, 0xc9, 0xd9, 0x32, 0x78, 0xcd, 0x8c, 0x2a, 0x3f, 0x0a, 0xa4, 0x50, 0x8f, 0x23, - 0xd6, 0xf7, 0xb0, 0x9b, 0xb7, 0x46, 0x4c, 0x6c, 0x13, 0x54, 0xc6, 0x11, 0xde, 0x99, 0x5a, 0x7b, - 0x77, 0x35, 0x4b, 0x1c, 0x7d, 0x21, 0x11, 0xc1, 0x63, 0x13, 0x2a, 0xe7, 0x4e, 0x1c, 0x78, 0x81, - 0xcb, 0x3b, 0xa5, 0xbd, 0x90, 0x48, 0x0e, 0x74, 0xab, 0xa0, 0xc6, 0x94, 0x2d, 0xfd, 0xc4, 0xfa, - 0x0d, 0xc1, 0x43, 0xde, 0x9e, 0x81, 0xb3, 0x58, 0x4f, 0xc0, 0xbd, 0x8a, 0xa1, 0x2d, 0x14, 0x93, - 0xb7, 0x53, 0xcc, 0x7a, 0x0e, 0x78, 0xf3, 0xb4, 0x42, 0x94, 0x3a, 0x94, 0x83, 0x14, 0xe0, 0xe3, - 0xae, 0x91, 0xcc, 0xc0, 0x26, 0x54, 0x45, 0xbd, 0xcc, 0x90, 0x39, 0xb1, 0xb2, 0xad, 0xdf, 0x91, - 0x08, 0xf4, 0xca, 0xf1, 0x97, 0xeb, 0xba, 0xeb, 0x50, 0xe6, 0xb7, 0x82, 0xd7, 0xa8, 0x91, 0xcc, - 0xb8, 0x5f, 0x0d, 0x79, 0x0b, 0x35, 0x94, 0x2d, 0xd5, 0xe8, 0xc3, 0x5e, 0xa1, 0x08, 0x21, 0xc7, - 0x63, 0x50, 0x7f, 0xe2, 0x88, 0xd0, 0x43, 0x58, 0xf7, 0x09, 0x72, 0x44, 0x40, 0x5b, 0xbd, 0x46, - 0xb8, 0x06, 0x95, 0xc9, 0xe0, 0x8b, 0xc1, 0x70, 0x3a, 0xd0, 0x25, 0xac, 0x41, 0xf9, 0xab, 0x89, - 0x4d, 0xbe, 0xd1, 0x11, 0xae, 0x42, 0x89, 0x4c, 0x5e, 0xda, 0xba, 0x9c, 0x7a, 0x8c, 0xfa, 0xcf, - 0xec, 0x5e, 0x87, 0xe8, 0x4a, 0xea, 0x31, 0x1a, 0x0f, 0x89, 0xad, 0x97, 0x52, 0x9c, 0xd8, 0x3d, - 0xbb, 0xff, 0xca, 0xd6, 0xcb, 0x47, 0x2d, 0x78, 0x72, 0x47, 0x49, 0x69, 0xa4, 0x69, 0x87, 0x88, - 0xf0, 0x9d, 0xee, 0x90, 0x8c, 0x75, 0x74, 0xd4, 0x85, 0x52, 0x7a, 0x77, 0x71, 0x05, 0x14, 0xd2, - 0x99, 0x66, 0x5c, 0x6f, 0x38, 0x19, 0x8c, 0x75, 0x94, 0x62, 0xa3, 0xc9, 0xb1, 0x2e, 0xa7, 0x8b, - 0xe3, 0xfe, 0x40, 0x57, 0xf8, 0xa2, 0xf3, 0x75, 0x96, 0x93, 0x7b, 0xd9, 0x44, 0x2f, 0xb7, 0x7f, - 0x96, 0xa1, 0xcc, 0x0b, 0xc1, 0x1f, 0x42, 0x29, 0x7d, 0xeb, 0xf1, 0x5e, 0x2e, 0xef, 0xc6, 0x4f, - 0x60, 0xd6, 0x8b, 0xa0, 0x10, 0xee, 0x33, 0x50, 0xb3, 0x6b, 0x84, 0x1f, 0x15, 0xaf, 0x55, 0xbe, - 0xed, 0xf1, 0x7f, 0xe1, 0x6c, 0xe3, 0x07, 0x08, 0xf7, 0x00, 0xd6, 0x83, 0x89, 0xf7, 0x0b, 0x2f, - 0xdf, 0xe6, 0xd5, 0x32, 0xcd, 0xdb, 0x28, 0x91, 0xff, 0x39, 0xd4, 0x36, 0xfa, 0x89, 0x8b, 0xae, - 0x85, 0x49, 0x35, 0xdf, 0xb9, 0x95, 0xcb, 0xe2, 0x74, 0xdf, 0xbd, 0xfa, 0xa7, 0x21, 0x5d, 0x5d, - 0x37, 0xd0, 0x9b, 0xeb, 0x06, 0xfa, 0xfb, 0xba, 0x81, 0x7e, 0xb9, 0x69, 0x48, 0x6f, 0x6e, 0x1a, - 0xd2, 0x1f, 0x37, 0x0d, 0xe9, 0xdb, 0x0a, 0xff, 0x6b, 0xa2, 0xf9, 0x5c, 0xe5, 0x9f, 0xe4, 0x47, - 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xa5, 0x34, 0x17, 0xba, 0x5c, 0x07, 0x00, 0x00, + // 934 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcb, 0x6e, 0x23, 0x45, + 0x14, 0x75, 0xbb, 0xfd, 0xbc, 0x4e, 0x4c, 0x4f, 0xc5, 0xc9, 0x74, 0x8c, 0xe4, 0x58, 0x2d, 0x21, + 0x59, 0x01, 0x39, 0xe0, 0x11, 0x20, 0xd0, 0x6c, 0x6c, 0x8f, 0x47, 0x63, 0x31, 0x71, 0xa0, 0x6c, + 0x8f, 0x79, 0x2c, 0x4c, 0xdb, 0x29, 0xda, 0xad, 0x71, 0x3f, 0xe8, 0x2a, 0x93, 0x64, 0xc3, 0x82, + 0x2f, 0x60, 0xcb, 0x3f, 0xf0, 0x17, 0x6c, 0xb2, 0x9c, 0x25, 0x6c, 0x10, 0x24, 0x3f, 0x82, 0xaa, + 0xba, 0xda, 0xee, 0x0e, 0x49, 0xa4, 0x51, 0x76, 0x75, 0xcf, 0xb9, 0xbe, 0x8f, 0x53, 0xf7, 0x76, + 0x19, 0x8a, 0x81, 0x3f, 0x6f, 0xfa, 0x81, 0xc7, 0x3c, 0x94, 0x63, 0x0b, 0xd3, 0xf5, 0x68, 0xb5, + 0xc4, 0x2e, 0x7c, 0x42, 0x43, 0xb0, 0x5a, 0xb1, 0x3c, 0xcb, 0x13, 0xc7, 0x23, 0x7e, 0x92, 0xe8, + 0x13, 0xcb, 0x66, 0x8b, 0xd5, 0xac, 0x39, 0xf7, 0x9c, 0x23, 0x3f, 0xf0, 0x1c, 0xc2, 0x16, 0x64, + 0x45, 0x6f, 0x1e, 0xfd, 0xd9, 0x51, 0x2c, 0x94, 0xf1, 0x0e, 0x6c, 0x4f, 0x02, 0x9b, 0x11, 0x4c, + 0xa8, 0xef, 0xb9, 0x94, 0x18, 0x3f, 0xc3, 0x96, 0x04, 0x7e, 0x5c, 0x11, 0xca, 0xd0, 0x53, 0x00, + 0x66, 0x3b, 0x84, 0x92, 0xc0, 0x26, 0x54, 0x57, 0xea, 0x6a, 0xa3, 0xd4, 0xda, 0x6b, 0x6e, 0x82, + 0x36, 0x47, 0xb6, 0x43, 0x86, 0x82, 0xed, 0x64, 0x2e, 0xff, 0x3e, 0x48, 0xe1, 0x98, 0x3f, 0xda, + 0x83, 0x1c, 0x23, 0xae, 0xe9, 0x32, 0x3d, 0x5d, 0x57, 0x1a, 0x45, 0x2c, 0x2d, 0xa4, 0x43, 0x3e, + 0x20, 0xfe, 0xd2, 0x9e, 0x9b, 0xba, 0x5a, 0x57, 0x1a, 0x2a, 0x8e, 0x4c, 0x63, 0x1b, 0x4a, 0x7d, + 0xf7, 0x07, 0x4f, 0xa6, 0x37, 0xfe, 0x52, 0x60, 0x2b, 0xb4, 0xc3, 0xfa, 0xd0, 0xfb, 0x90, 0x5b, + 0x9a, 0x33, 0xb2, 0x8c, 0x6a, 0xd9, 0x6e, 0x86, 0x0a, 0x35, 0x5f, 0x72, 0x54, 0x96, 0x20, 0x5d, + 0xd0, 0x3e, 0x14, 0x1c, 0xdb, 0x9d, 0xf2, 0x82, 0x44, 0x01, 0x2a, 0xce, 0x3b, 0xb6, 0xcb, 0x2b, + 0x16, 0x94, 0x79, 0x1e, 0x52, 0xb2, 0x04, 0xc7, 0x3c, 0x17, 0xd4, 0x11, 0x14, 0x29, 0xf3, 0x02, + 0x32, 0xba, 0xf0, 0x89, 0x9e, 0xa9, 0x2b, 0x8d, 0x72, 0xeb, 0x51, 0x94, 0x65, 0x18, 0x11, 0x78, + 0xe3, 0x83, 0x3e, 0x06, 0x10, 0x09, 0xa7, 0x94, 0x30, 0xaa, 0x67, 0x45, 0x5d, 0x5a, 0xa2, 0xae, + 0x21, 0x61, 0xb2, 0xb4, 0xe2, 0x52, 0xda, 0xd4, 0xf8, 0x14, 0x0a, 0x11, 0xf9, 0x56, 0x6d, 0x19, + 0xbf, 0xa9, 0xb0, 0x1d, 0x4a, 0x1e, 0xdd, 0x52, 0xbc, 0x51, 0xe5, 0xee, 0x46, 0xd3, 0xc9, 0x46, + 0x3f, 0xe1, 0x14, 0x9b, 0x2f, 0x48, 0x40, 0x75, 0x55, 0xa4, 0xad, 0x24, 0xd2, 0x1e, 0x87, 0xa4, + 0xcc, 0xbe, 0xf6, 0x45, 0x2d, 0xd8, 0xe5, 0x21, 0x03, 0x42, 0xbd, 0xe5, 0x8a, 0xd9, 0x9e, 0x3b, + 0x3d, 0xb3, 0xdd, 0x53, 0xef, 0x4c, 0x88, 0xa5, 0xe2, 0x1d, 0xc7, 0x3c, 0xc7, 0x6b, 0x6e, 0x22, + 0x28, 0xf4, 0x01, 0x80, 0x69, 0x59, 0x01, 0xb1, 0x4c, 0x46, 0x42, 0x8d, 0xca, 0xad, 0xad, 0x28, + 0x5b, 0xdb, 0xb2, 0x02, 0x1c, 0xe3, 0xd1, 0xe7, 0xb0, 0xef, 0x9b, 0x01, 0xb3, 0xcd, 0x25, 0xcf, + 0x22, 0x6e, 0x7e, 0x7a, 0x6a, 0x53, 0x73, 0xb6, 0x24, 0xa7, 0x7a, 0xae, 0xae, 0x34, 0x0a, 0xf8, + 0xb1, 0x74, 0x88, 0x26, 0xe3, 0x99, 0xa4, 0xd1, 0x77, 0xb7, 0xfc, 0x96, 0xb2, 0xc0, 0x64, 0xc4, + 0xba, 0xd0, 0xf3, 0xe2, 0x3a, 0x0f, 0xa2, 0xc4, 0x5f, 0x26, 0x63, 0x0c, 0xa5, 0xdb, 0xff, 0x82, + 0x47, 0x04, 0x3a, 0x80, 0x12, 0x7d, 0x6d, 0xfb, 0xd3, 0xf9, 0x62, 0xe5, 0xbe, 0xa6, 0x7a, 0x41, + 0x94, 0x02, 0x1c, 0xea, 0x0a, 0xc4, 0xf8, 0x1e, 0xca, 0xd1, 0xd5, 0xc8, 0x89, 0x6d, 0x40, 0x6e, + 0xbd, 0x3d, 0x4a, 0xa3, 0xd4, 0x2a, 0xaf, 0x67, 0x49, 0xa0, 0x2f, 0x52, 0x58, 0xf2, 0xa8, 0x0a, + 0xf9, 0x33, 0x33, 0x70, 0x6d, 0xd7, 0x0a, 0xd7, 0xe5, 0x45, 0x0a, 0x47, 0x40, 0xa7, 0x00, 0xb9, + 0x80, 0xd0, 0xd5, 0x92, 0x19, 0xbf, 0x2b, 0xf0, 0x48, 0x5c, 0xcf, 0xc0, 0x74, 0x36, 0x13, 0x70, + 0xaf, 0x62, 0xca, 0x03, 0x14, 0x4b, 0x3f, 0x4c, 0x31, 0xe3, 0x39, 0xa0, 0x78, 0xb5, 0x52, 0x94, + 0x0a, 0x64, 0x5d, 0x0e, 0x88, 0x71, 0x2f, 0xe2, 0xd0, 0x40, 0x55, 0x28, 0xc8, 0x7e, 0xa9, 0x9e, + 0x16, 0xc4, 0xda, 0x36, 0xfe, 0x50, 0x64, 0xa0, 0x57, 0xe6, 0x72, 0xb5, 0xe9, 0xbb, 0x02, 0x59, + 0xb1, 0x15, 0xa2, 0xc7, 0x22, 0x0e, 0x8d, 0xfb, 0xd5, 0x48, 0x3f, 0x40, 0x0d, 0xf5, 0x81, 0x6a, + 0xf4, 0x61, 0x27, 0xd1, 0x84, 0x94, 0x63, 0x0f, 0x72, 0x3f, 0x09, 0x44, 0xea, 0x21, 0xad, 0xfb, + 0x04, 0x39, 0xc4, 0x50, 0x5c, 0x7f, 0x8d, 0x50, 0x09, 0xf2, 0xe3, 0xc1, 0x17, 0x83, 0x93, 0xc9, + 0x40, 0x4b, 0xa1, 0x22, 0x64, 0xbf, 0x1a, 0xf7, 0xf0, 0x37, 0x9a, 0x82, 0x0a, 0x90, 0xc1, 0xe3, + 0x97, 0x3d, 0x2d, 0xcd, 0x3d, 0x86, 0xfd, 0x67, 0xbd, 0x6e, 0x1b, 0x6b, 0x2a, 0xf7, 0x18, 0x8e, + 0x4e, 0x70, 0x4f, 0xcb, 0x70, 0x1c, 0xf7, 0xba, 0xbd, 0xfe, 0xab, 0x9e, 0x96, 0x3d, 0x6c, 0xc2, + 0xe3, 0x3b, 0x5a, 0xe2, 0x91, 0x26, 0x6d, 0x2c, 0xc3, 0xb7, 0x3b, 0x27, 0x78, 0xa4, 0x29, 0x87, + 0x1d, 0xc8, 0xf0, 0xdd, 0x45, 0x79, 0x50, 0x71, 0x7b, 0x12, 0x72, 0xdd, 0x93, 0xf1, 0x60, 0xa4, + 0x29, 0x1c, 0x1b, 0x8e, 0x8f, 0xb5, 0x34, 0x3f, 0x1c, 0xf7, 0x07, 0x9a, 0x2a, 0x0e, 0xed, 0xaf, + 0xc3, 0x9c, 0xc2, 0xab, 0x87, 0xb5, 0x6c, 0xeb, 0x97, 0x34, 0x64, 0x45, 0x23, 0xe8, 0x23, 0xc8, + 0xf0, 0x6f, 0x3d, 0xda, 0x89, 0xe4, 0x8d, 0xbd, 0x04, 0xd5, 0x4a, 0x12, 0x94, 0xc2, 0x7d, 0x06, + 0xb9, 0x70, 0x8d, 0xd0, 0x6e, 0x72, 0xad, 0xa2, 0x9f, 0xed, 0xdd, 0x84, 0xc3, 0x1f, 0x7e, 0xa8, + 0xa0, 0x2e, 0xc0, 0x66, 0x30, 0xd1, 0x7e, 0xe2, 0xcb, 0x17, 0x5f, 0xad, 0x6a, 0xf5, 0x36, 0x4a, + 0xe6, 0x7f, 0x0e, 0xa5, 0xd8, 0x7d, 0xa2, 0xa4, 0x6b, 0x62, 0x52, 0xab, 0xef, 0xde, 0xca, 0x85, + 0x71, 0x5a, 0x03, 0x28, 0x8b, 0x67, 0x97, 0x8f, 0x60, 0x28, 0xc6, 0x53, 0x28, 0x61, 0xe2, 0x78, + 0x8c, 0x08, 0x1c, 0xad, 0xdb, 0x8f, 0xbf, 0xce, 0xd5, 0xdd, 0x1b, 0xa8, 0x7c, 0xc4, 0x53, 0x9d, + 0xf7, 0x2e, 0xff, 0xad, 0xa5, 0x2e, 0xaf, 0x6a, 0xca, 0x9b, 0xab, 0x9a, 0xf2, 0xcf, 0x55, 0x4d, + 0xf9, 0xf5, 0xba, 0x96, 0x7a, 0x73, 0x5d, 0x4b, 0xfd, 0x79, 0x5d, 0x4b, 0x7d, 0x9b, 0x17, 0x6f, + 0x97, 0x3f, 0x9b, 0xe5, 0xc4, 0xbf, 0x80, 0x27, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x67, 0x56, + 0x73, 0x8e, 0x72, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -849,6 +935,152 @@ var _Store_serviceDesc = grpc.ServiceDesc{ Metadata: "rpc.proto", } +// WriteableStoreClient is the client API for WriteableStore service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type WriteableStoreClient interface { + // WriteRequest allows you to write metrics to this store via remote write + RemoteWrite(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error) +} + +type writeableStoreClient struct { + cc *grpc.ClientConn +} + +func NewWriteableStoreClient(cc *grpc.ClientConn) WriteableStoreClient { + return &writeableStoreClient{cc} +} + +func (c *writeableStoreClient) RemoteWrite(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error) { + out := new(WriteResponse) + err := c.cc.Invoke(ctx, "/thanos.WriteableStore/RemoteWrite", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// WriteableStoreServer is the server API for WriteableStore service. +type WriteableStoreServer interface { + // WriteRequest allows you to write metrics to this store via remote write + RemoteWrite(context.Context, *WriteRequest) (*WriteResponse, error) +} + +// UnimplementedWriteableStoreServer can be embedded to have forward compatible implementations. +type UnimplementedWriteableStoreServer struct { +} + +func (*UnimplementedWriteableStoreServer) RemoteWrite(ctx context.Context, req *WriteRequest) (*WriteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoteWrite not implemented") +} + +func RegisterWriteableStoreServer(s *grpc.Server, srv WriteableStoreServer) { + s.RegisterService(&_WriteableStore_serviceDesc, srv) +} + +func _WriteableStore_RemoteWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(WriteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WriteableStoreServer).RemoteWrite(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/thanos.WriteableStore/RemoteWrite", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WriteableStoreServer).RemoteWrite(ctx, req.(*WriteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _WriteableStore_serviceDesc = grpc.ServiceDesc{ + ServiceName: "thanos.WriteableStore", + HandlerType: (*WriteableStoreServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "RemoteWrite", + Handler: _WriteableStore_RemoteWrite_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "rpc.proto", +} + +func (m *WriteResponse) 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 *WriteResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WriteResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *WriteRequest) 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 *WriteRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WriteRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Replica != 0 { + i = encodeVarintRpc(dAtA, i, uint64(m.Replica)) + i-- + dAtA[i] = 0x18 + } + if len(m.Tenant) > 0 { + i -= len(m.Tenant) + copy(dAtA[i:], m.Tenant) + i = encodeVarintRpc(dAtA, i, uint64(len(m.Tenant))) + i-- + dAtA[i] = 0x12 + } + 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 = encodeVarintRpc(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *InfoRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1313,6 +1545,37 @@ func encodeVarintRpc(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *WriteResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *WriteRequest) 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 + sovRpc(uint64(l)) + } + } + l = len(m.Tenant) + if l > 0 { + n += 1 + l + sovRpc(uint64(l)) + } + if m.Replica != 0 { + n += 1 + sovRpc(uint64(m.Replica)) + } + return n +} + func (m *InfoRequest) Size() (n int) { if m == nil { return 0 @@ -1523,6 +1786,197 @@ func sovRpc(x uint64) (n int) { func sozRpc(x uint64) (n int) { return sovRpc(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (m *WriteResponse) 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 ErrIntOverflowRpc + } + 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: WriteResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WriteResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipRpc(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRpc + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthRpc + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *WriteRequest) 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 ErrIntOverflowRpc + } + 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: WriteRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WriteRequest: 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 ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRpc + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRpc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Timeseries = append(m.Timeseries, prompb.TimeSeries{}) + if err := m.Timeseries[len(m.Timeseries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRpc + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRpc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenant = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Replica", wireType) + } + m.Replica = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Replica |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipRpc(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRpc + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthRpc + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *InfoRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/storepb/rpc.proto b/vendor/github.com/thanos-io/thanos/pkg/store/storepb/rpc.proto index 219262f207e..c314c40f080 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/storepb/rpc.proto +++ b/vendor/github.com/thanos-io/thanos/pkg/store/storepb/rpc.proto @@ -1,8 +1,12 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + syntax = "proto3"; package thanos; import "types.proto"; import "gogoproto/gogo.proto"; +import "github.com/prometheus/prometheus/prompb/types.proto"; option go_package = "storepb"; @@ -39,6 +43,21 @@ service Store { rpc LabelValues(LabelValuesRequest) returns (LabelValuesResponse); } +/// WriteableStore reprents API against instance that stores XOR encoded values with label set metadata (e.g Prometheus metrics). +service WriteableStore { + // WriteRequest allows you to write metrics to this store via remote write + rpc RemoteWrite(WriteRequest) returns (WriteResponse) {} +} + +message WriteResponse { +} + +message WriteRequest { + repeated prometheus.TimeSeries timeseries = 1 [(gogoproto.nullable) = false]; + string tenant = 2; + int64 replica = 3; +} + message InfoRequest { } @@ -108,11 +127,11 @@ enum Aggr { message SeriesResponse { oneof result { - Series series = 1; + Series series = 1; - /// warning is considered an information piece in place of series for warning purposes. - /// It is used to warn query customer about suspicious cases or partial response (if enabled). - string warning = 2; + /// warning is considered an information piece in place of series for warning purposes. + /// It is used to warn query customer about suspicious cases or partial response (if enabled). + string warning = 2; } } diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/storepb/types.proto b/vendor/github.com/thanos-io/thanos/pkg/store/storepb/types.proto index 24c9f4b3182..635aa504696 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/storepb/types.proto +++ b/vendor/github.com/thanos-io/thanos/pkg/store/storepb/types.proto @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + syntax = "proto3"; package thanos; diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/tsdb.go b/vendor/github.com/thanos-io/thanos/pkg/store/tsdb.go index 40de141811a..076af640fe8 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/tsdb.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/tsdb.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package store import ( @@ -28,6 +31,12 @@ type TSDBStore struct { externalLabels labels.Labels } +// ReadWriteTSDBStore is a TSDBStore that can also be written to. +type ReadWriteTSDBStore struct { + storepb.StoreServer + storepb.WriteableStoreServer +} + // NewTSDBStore creates a new TSDBStore. func NewTSDBStore(logger log.Logger, _ prometheus.Registerer, db *tsdb.DB, component component.SourceStoreAPI, externalLabels labels.Labels) *TSDBStore { if logger == nil { diff --git a/vendor/github.com/thanos-io/thanos/pkg/strutil/merge.go b/vendor/github.com/thanos-io/thanos/pkg/strutil/merge.go index 7a7d4f95090..d6108771f44 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/strutil/merge.go +++ b/vendor/github.com/thanos-io/thanos/pkg/strutil/merge.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package strutil import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/testutil/testorbench.go b/vendor/github.com/thanos-io/thanos/pkg/testutil/testorbench.go new file mode 100644 index 00000000000..dcfbff11ed7 --- /dev/null +++ b/vendor/github.com/thanos-io/thanos/pkg/testutil/testorbench.go @@ -0,0 +1,75 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package testutil + +import ( + "testing" +) + +// TB represents union of test and benchmark. +// This allows the same test suite to be run by both benchmark and test, helping to reuse more code. +// The reason is that usually benchmarks are not being run on CI, especially for short tests, so you need to recreate +// usually similar tests for `Test(t *testing.T)` methods. Example of usage is presented here: +// +// func TestTestOrBench(t *testing.T) { +// tb := NewTB(t) +// tb.Run("1", func(tb TB) { testorbenchComplexTest(tb) }) +// tb.Run("2", func(tb TB) { testorbenchComplexTest(tb) }) +// } +// +// func BenchmarkTestOrBench(b *testing.B) { +// tb := NewTB(t) +// tb.Run("1", func(tb TB) { testorbenchComplexTest(tb) }) +// tb.Run("2", func(tb TB) { testorbenchComplexTest(tb) }) +// } +type TB interface { + testing.TB + IsBenchmark() bool + Run(name string, f func(t TB)) bool + N() int + ResetTimer() +} + +// tb implements TB as well as testing.TB interfaces. +type tb struct { + testing.TB +} + +// NewTB creates tb from testing.TB. +func NewTB(t testing.TB) TB { return &tb{TB: t} } + +// Run benchmarks/tests f as a subbenchmark/subtest with the given name. It reports +// whether there were any failures. +// +// A subbenchmark/subtest is like any other benchmark/test. +func (t *tb) Run(name string, f func(t TB)) bool { + if b, ok := t.TB.(*testing.B); ok { + return b.Run(name, func(nested *testing.B) { f(&tb{TB: nested}) }) + } + if t, ok := t.TB.(*testing.T); ok { + return t.Run(name, func(nested *testing.T) { f(&tb{TB: nested}) }) + } + panic("not a benchmark and not a test") +} + +// N returns number of iterations to do for benchmark, 1 in case of test. +func (t *tb) N() int { + if b, ok := t.TB.(*testing.B); ok { + return b.N + } + return 1 +} + +// ResetTimer resets a timer, if it's a benchmark, noop otherwise. +func (t *tb) ResetTimer() { + if b, ok := t.TB.(*testing.B); ok { + b.ResetTimer() + } +} + +// IsBenchmark returns true if it's a benchmark. +func (t *tb) IsBenchmark() bool { + _, ok := t.TB.(*testing.B) + return ok +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/testutil/testutil.go b/vendor/github.com/thanos-io/thanos/pkg/testutil/testutil.go new file mode 100644 index 00000000000..f4a3933fb41 --- /dev/null +++ b/vendor/github.com/thanos-io/thanos/pkg/testutil/testutil.go @@ -0,0 +1,98 @@ +// The MIT License (MIT) + +// Copyright (c) 2014 Ben Johnson + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package testutil + +import ( + "fmt" + "path/filepath" + "reflect" + "runtime" + "testing" + + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" +) + +// Assert fails the test if the condition is false. +func Assert(tb testing.TB, condition bool, msg string, v ...interface{}) { + if !condition { + _, file, line, _ := runtime.Caller(1) + fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...) + tb.FailNow() + } +} + +// Ok fails the test if an err is not nil. +func Ok(tb testing.TB, err error) { + if err != nil { + _, file, line, _ := runtime.Caller(1) + fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error()) + tb.FailNow() + } +} + +// NotOk fails the test if an err is nil. +func NotOk(tb testing.TB, err error) { + if err == nil { + _, file, line, _ := runtime.Caller(1) + fmt.Printf("\033[31m%s:%d: expected error, got nothing \033[39m\n\n", filepath.Base(file), line) + tb.FailNow() + } +} + +// Equals fails the test if exp is not equal to act. +func Equals(tb testing.TB, exp, act interface{}, v ...interface{}) { + if !reflect.DeepEqual(exp, act) { + _, file, line, _ := runtime.Caller(1) + + var msg string + if len(v) > 0 { + msg = fmt.Sprintf(v[0].(string), v[1:]...) + } + + fmt.Printf("\033[31m%s:%d:"+msg+"\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act) + tb.FailNow() + } +} + +// GatherAndCompare compares the metrics of a Gatherers pair. +func GatherAndCompare(t *testing.T, g1 prometheus.Gatherer, g2 prometheus.Gatherer, filter string) { + g1m, err := g1.Gather() + Ok(t, err) + g2m, err := g2.Gather() + Ok(t, err) + + var m1 *dto.MetricFamily + for _, m := range g1m { + if *m.Name == filter { + m1 = m + } + } + var m2 *dto.MetricFamily + for _, m := range g2m { + if *m.Name == filter { + m2 = m + } + } + Equals(t, m1.String(), m2.String()) +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/tracing/grpc.go b/vendor/github.com/thanos-io/thanos/pkg/tracing/grpc.go index 91c861ebb39..303c387a678 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/tracing/grpc.go +++ b/vendor/github.com/thanos-io/thanos/pkg/tracing/grpc.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package tracing import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/tracing/http.go b/vendor/github.com/thanos-io/thanos/pkg/tracing/http.go index 1344670fffd..f158f0e6f35 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/tracing/http.go +++ b/vendor/github.com/thanos-io/thanos/pkg/tracing/http.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package tracing import ( diff --git a/vendor/github.com/thanos-io/thanos/pkg/tracing/tracing.go b/vendor/github.com/thanos-io/thanos/pkg/tracing/tracing.go index f3031b48a51..9664cbc068a 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/tracing/tracing.go +++ b/vendor/github.com/thanos-io/thanos/pkg/tracing/tracing.go @@ -1,3 +1,6 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + package tracing import ( diff --git a/vendor/modules.txt b/vendor/modules.txt index 1777f0d6c63..26cc0ce90e8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -155,7 +155,7 @@ github.com/go-openapi/jsonpointer github.com/go-openapi/jsonreference # github.com/go-openapi/loads v0.19.2 github.com/go-openapi/loads -# github.com/go-openapi/runtime v0.19.3 +# github.com/go-openapi/runtime v0.19.4 github.com/go-openapi/runtime github.com/go-openapi/runtime/flagext github.com/go-openapi/runtime/logger @@ -168,7 +168,7 @@ github.com/go-openapi/runtime/security github.com/go-openapi/spec # github.com/go-openapi/strfmt v0.19.2 github.com/go-openapi/strfmt -# github.com/go-openapi/swag v0.19.4 +# github.com/go-openapi/swag v0.19.5 github.com/go-openapi/swag # github.com/go-openapi/validate v0.19.2 github.com/go-openapi/validate @@ -329,7 +329,7 @@ github.com/mattn/go-ieproxy github.com/matttproud/golang_protobuf_extensions/pbutil # github.com/miekg/dns v1.1.22 github.com/miekg/dns -# github.com/minio/minio-go/v6 v6.0.44 +# github.com/minio/minio-go/v6 v6.0.49 github.com/minio/minio-go/v6 github.com/minio/minio-go/v6/pkg/credentials github.com/minio/minio-go/v6/pkg/encrypt @@ -366,7 +366,7 @@ github.com/opentracing/opentracing-go/log github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib -# github.com/prometheus/alertmanager v0.19.0 +# github.com/prometheus/alertmanager v0.20.0 github.com/prometheus/alertmanager/api github.com/prometheus/alertmanager/api/metrics github.com/prometheus/alertmanager/api/v1 @@ -397,7 +397,7 @@ github.com/prometheus/alertmanager/notify/slack github.com/prometheus/alertmanager/notify/victorops github.com/prometheus/alertmanager/notify/webhook github.com/prometheus/alertmanager/notify/wechat -github.com/prometheus/alertmanager/pkg/parse +github.com/prometheus/alertmanager/pkg/labels github.com/prometheus/alertmanager/provider github.com/prometheus/alertmanager/provider/mem github.com/prometheus/alertmanager/silence @@ -517,7 +517,7 @@ github.com/stretchr/objx github.com/stretchr/testify/assert github.com/stretchr/testify/mock github.com/stretchr/testify/require -# github.com/thanos-io/thanos v0.8.1-0.20200109203923-552ffa4c1a0d +# github.com/thanos-io/thanos v0.11.0 github.com/thanos-io/thanos/pkg/block github.com/thanos-io/thanos/pkg/block/indexheader github.com/thanos-io/thanos/pkg/block/metadata @@ -542,6 +542,7 @@ github.com/thanos-io/thanos/pkg/store github.com/thanos-io/thanos/pkg/store/cache github.com/thanos-io/thanos/pkg/store/storepb github.com/thanos-io/thanos/pkg/strutil +github.com/thanos-io/thanos/pkg/testutil github.com/thanos-io/thanos/pkg/tracing # github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 github.com/tmc/grpc-websocket-proxy/wsproxy From 15b8278e589b89341de5320e1faab5fab6680902 Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Fri, 6 Mar 2020 15:25:14 +0100 Subject: [PATCH 2/4] Added PR number to CHANGELOG Signed-off-by: Marco Pracucci --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df7f63f755d..2572d0fa833 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ * [CHANGE] Experimental TSDB: the querier in-memory index cache used by the experimental blocks storage shifted from per-tenant to per-querier. The `-experimental.tsdb.bucket-store.index-cache-size-bytes` now configures the per-querier index cache max size instead of a per-tenant cache and its default has been increased to 1GB. #2189 * [CHANGE] If you are vendoring Cortex and use its components in your project, be aware that many Cortex components no longer start automatically when they are created. You may want to review PR and attached document. #2166 * [CHANGE] Cortex now has /ready probe for all services, not just ingester and querier as before. In single-binary mode, /ready reports 204 only if all components are running properly. #2166 -* [CHANGE] Experimental TSDB: switched the blocks storage index header to the binary format. This change is expected to have no visible impact, except lower startup times and memory usage in the queriers. It's possible to switch back to the old JSON format via the flag `-experimental.tsdb.bucket-store.binary-index-header-enabled=false`. +* [CHANGE] Experimental TSDB: switched the blocks storage index header to the binary format. This change is expected to have no visible impact, except lower startup times and memory usage in the queriers. It's possible to switch back to the old JSON format via the flag `-experimental.tsdb.bucket-store.binary-index-header-enabled=false`. #2223 * [FEATURE] Added a read-only local alertmanager config store using files named corresponding to their tenant id. #2125 * [FEATURE] Added user sub rings to distribute users to a subset of ingesters. #1947 * `--experimental.distributor.user-subring-size` From f727d0385c512ad5a6860a1c6373eb89b99a12e7 Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Fri, 6 Mar 2020 17:39:46 +0100 Subject: [PATCH 3/4] Do not call the Thanos JSON index header as 'legacy' Signed-off-by: Marco Pracucci --- docs/configuration/config-file-reference.md | 2 +- docs/operations/blocks-storage.md | 2 +- pkg/storage/tsdb/config.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration/config-file-reference.md b/docs/configuration/config-file-reference.md index 469bd1cceb4..ddf368de84f 100644 --- a/docs/configuration/config-file-reference.md +++ b/docs/configuration/config-file-reference.md @@ -2199,7 +2199,7 @@ bucket_store: [meta_sync_concurrency: | default = 20] # Whether the bucket store should use the binary index header. If false, it - # uses the legacy JSON index header. + # uses the JSON index header. # CLI flag: -experimental.tsdb.bucket-store.binary-index-header-enabled [binary_index_header_enabled: | default = true] diff --git a/docs/operations/blocks-storage.md b/docs/operations/blocks-storage.md index 2a22c241b19..9ed346cad0a 100644 --- a/docs/operations/blocks-storage.md +++ b/docs/operations/blocks-storage.md @@ -167,7 +167,7 @@ tsdb: [meta_sync_concurrency: | default = 20] # Whether the bucket store should use the binary index header. If false, it - # uses the legacy JSON index header. + # uses the JSON index header. # CLI flag: -experimental.tsdb.bucket-store.binary-index-header-enabled [binary_index_header_enabled: | default = true] diff --git a/pkg/storage/tsdb/config.go b/pkg/storage/tsdb/config.go index 4b871109bde..a19dfdcf578 100644 --- a/pkg/storage/tsdb/config.go +++ b/pkg/storage/tsdb/config.go @@ -170,7 +170,7 @@ func (cfg *BucketStoreConfig) RegisterFlags(f *flag.FlagSet) { f.IntVar(&cfg.TenantSyncConcurrency, "experimental.tsdb.bucket-store.tenant-sync-concurrency", 10, "Maximum number of concurrent tenants synching blocks.") f.IntVar(&cfg.BlockSyncConcurrency, "experimental.tsdb.bucket-store.block-sync-concurrency", 20, "Maximum number of concurrent blocks synching per tenant.") f.IntVar(&cfg.MetaSyncConcurrency, "experimental.tsdb.bucket-store.meta-sync-concurrency", 20, "Number of Go routines to use when syncing block meta files from object storage per tenant.") - f.BoolVar(&cfg.BinaryIndexHeader, "experimental.tsdb.bucket-store.binary-index-header-enabled", true, "Whether the bucket store should use the binary index header. If false, it uses the legacy JSON index header.") + f.BoolVar(&cfg.BinaryIndexHeader, "experimental.tsdb.bucket-store.binary-index-header-enabled", true, "Whether the bucket store should use the binary index header. If false, it uses the JSON index header.") f.DurationVar(&cfg.ConsistencyDelay, "experimental.tsdb.bucket-store.consistency-delay", 0, "Minimum age of a block before it's being read. Set it to safe value (e.g 30m) if your object storage is eventually consistent. GCS and S3 are (roughly) strongly consistent.") } From 6fb18af83cc6efa492d736728f324b19b426e6d3 Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Fri, 6 Mar 2020 17:45:50 +0100 Subject: [PATCH 4/4] Improved comment about the dispatcher metrics singleton Signed-off-by: Marco Pracucci --- pkg/alertmanager/alertmanager.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/alertmanager/alertmanager.go b/pkg/alertmanager/alertmanager.go index 43fb11bc572..5f17a82213f 100644 --- a/pkg/alertmanager/alertmanager.go +++ b/pkg/alertmanager/alertmanager.go @@ -75,9 +75,11 @@ type Alertmanager struct { var ( webReload = make(chan chan error) - // Workaround a bug in the alertmanager which doesn't register the - // metrics in the input registry but to the global default one. - // TODO change once the vendored alertmanager will have this PR merged into: + // In order to workaround a bug in the alertmanager, which doesn't register the + // metrics in the input registry but to the global default one, we do define a + // singleton dispatcher metrics instance that is going to be shared across all + // tenants alertmanagers. + // TODO change this once the vendored alertmanager will have this PR merged into: // https://github.com/prometheus/alertmanager/pull/2200 dispatcherMetrics = dispatch.NewDispatcherMetrics(prometheus.NewRegistry()) )